Introduce a matcher for one or more matched digits
All checks were successful
Build / audit (push) Successful in 8s
Build / test (push) Successful in 16m3s

This commit is contained in:
Eugen Wissner 2024-09-13 21:58:13 +02:00
parent 74da0eb391
commit 3dde41e0d4
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
2 changed files with 21 additions and 12 deletions

View File

@ -62,8 +62,8 @@ data MatchState = MatchState
data MatchToken data MatchToken
= OpenParenMatchToken = OpenParenMatchToken
| CloseParenMatchToken | CloseParenMatchToken
| AsteriskMatchToken
| SymbolMatchToken Char | SymbolMatchToken Char
| AtLeastMatchToken [Char]
| OneOfMatchToken [Char] | OneOfMatchToken [Char]
deriving (Eq, Show) deriving (Eq, Show)
@ -76,6 +76,7 @@ data MatchToken
-- * ( ) - The text in parentheses is matched but no saved in the resulting -- * ( ) - The text in parentheses is matched but no saved in the resulting
-- string. -- string.
-- * \\d - Matches zero or more digits. -- * \\d - Matches zero or more digits.
-- * \\D - Matches one or more digits.
-- * \\. - Matches zero or more digits or dots. -- * \\. - Matches zero or more digits or dots.
-- * \\\\ - Matches a back slash. -- * \\\\ - Matches a back slash.
-- * * - Matches everything. -- * * - Matches everything.
@ -103,20 +104,21 @@ match fullPattern = go startState
go (state{ ignoring = True, pattern' = tokens }) input' go (state{ ignoring = True, pattern' = tokens }) input'
go state@MatchState{ pattern' = CloseParenMatchToken : tokens } input' = go state@MatchState{ pattern' = CloseParenMatchToken : tokens } input' =
go (state{ ignoring = False, pattern' = tokens }) input' go (state{ ignoring = False, pattern' = tokens }) input'
go state@MatchState{ pattern' = AsteriskMatchToken : tokens } input' go state@MatchState{ pattern' = SymbolMatchToken patternCharacter : tokens } input'
| Just (nextCharacter, leftOver) <- Text.uncons input' = | Just (nextCharacter, leftOver) <- Text.uncons input'
go (matchSymbolToken state nextCharacter) leftOver , patternCharacter == nextCharacter =
| otherwise = go state{ pattern' = tokens } "" go (matchSymbolToken state{ pattern' = tokens } nextCharacter) leftOver
| otherwise = Nothing
go state@MatchState{ pattern' = OneOfMatchToken chars : tokens } input' go state@MatchState{ pattern' = OneOfMatchToken chars : tokens } input'
| Just (nextCharacter, leftOver) <- Text.uncons input' | Just (nextCharacter, leftOver) <- Text.uncons input'
, nextCharacter `elem` chars = , nextCharacter `elem` chars =
go (matchSymbolToken state nextCharacter) leftOver go (matchSymbolToken state nextCharacter) leftOver
| otherwise = | otherwise =
go (state{ pattern' = tokens }) input' go (state{ pattern' = tokens }) input'
go state@MatchState{ pattern' = SymbolMatchToken patternCharacter : tokens } input' go state@MatchState{ pattern' = AtLeastMatchToken chars : tokens } input'
| Just (nextCharacter, leftOver) <- Text.uncons input' | Just (nextCharacter, leftOver) <- Text.uncons input'
, patternCharacter == nextCharacter = , nextCharacter `elem` chars =
go (matchSymbolToken state{ pattern' = tokens } nextCharacter) leftOver go (matchSymbolToken state{ pattern' = OneOfMatchToken chars : tokens } nextCharacter) leftOver
| otherwise = Nothing | otherwise = Nothing
-- All tokens are processed, but there is still some input left. -- All tokens are processed, but there is still some input left.
go MatchState{ pattern' = [] } _ = Nothing go MatchState{ pattern' = [] } _ = Nothing
@ -134,7 +136,9 @@ parsePattern input'
Nothing -> [] Nothing -> []
Just ('d', remaining') -> OneOfMatchToken digits Just ('d', remaining') -> OneOfMatchToken digits
: parsePattern remaining' : parsePattern remaining'
Just ('.', remaining') -> OneOfMatchToken ('.' : digits) Just ('D', remaining') -> AtLeastMatchToken digits
: parsePattern remaining'
Just ('.', remaining') -> AtLeastMatchToken ('.' : digits)
: parsePattern remaining' : parsePattern remaining'
Just ('\\', remaining') -> SymbolMatchToken '\\' Just ('\\', remaining') -> SymbolMatchToken '\\'
: parsePattern remaining' : parsePattern remaining'
@ -147,11 +151,11 @@ parsePattern input'
| Just (firstChar, remaining) <- Text.uncons input' = | Just (firstChar, remaining) <- Text.uncons input' =
let token = let token =
case firstChar of case firstChar of
'*' -> AsteriskMatchToken '*' -> OneOfMatchToken (toEnum <$> [32 .. 127])
'(' -> OpenParenMatchToken '(' -> OpenParenMatchToken
')' -> CloseParenMatchToken ')' -> CloseParenMatchToken
s -> SymbolMatchToken s s -> SymbolMatchToken s
in token : parsePattern remaining in token : parsePattern remaining
| otherwise = [] | otherwise = []
where where
digits = toEnum <$> [fromEnum '0' .. fromEnum '9'] digits = toEnum <$> [fromEnum '0' .. fromEnum '9']

View File

@ -27,7 +27,7 @@ spec = do
actual = match "(v)2.6.\\d" "v2.6.0" actual = match "(v)2.6.\\d" "v2.6.0"
in actual `shouldBe` expected in actual `shouldBe` expected
it "matches digits and dot" $ it "matches digits and dots" $
let expected = Just "2.6.0" let expected = Just "2.6.0"
actual = match "(v)\\." "v2.6.0" actual = match "(v)\\." "v2.6.0"
in actual `shouldBe` expected in actual `shouldBe` expected
@ -46,3 +46,8 @@ spec = do
let expected = Just "abc" let expected = Just "abc"
actual = match "abc\\d\\d" "abc" actual = match "abc\\d\\d" "abc"
in actual `shouldBe` expected in actual `shouldBe` expected
it "matches at least one digit" $
let expected = Nothing
actual = match "1.\\D.3" "1..3"
in actual `shouldBe` expected