|
|
1
sshine
6 年前
F12
,则,
F 12
,则,
F1(a)
,则,
F2a
,则,
F5-A
,则,
F34-5
这是一个不完整的描述,所以我会做一些猜测。
-
我将首先定义一个类型,该类型可以包含这些表达式的逻辑部分。E、 g。
newtype F = F (Int, Maybe String) deriving Show
也就是说,“F”后跟一个数字和可选部分,可以是字母、括号中的字母,也可以是破折号后跟字母/数字。由于“F”后面的数字可以有多个数字,我假设可选字母/数字也可以是多个。
由于示例有限,我假设以下内容无效:
F1a(b)
,则,
F1(a)b
,则,
F1a-5
,则,
F1(a)-A
,则,
F1a(a)-5
,则,
F1a1
,则,
F1-(a)
,并确认以下各项有效:
F1A
,则,
F1abc
,则,
F1(abc)
,则,
F1-abc
,则,
F1-a1b2
.这可能不是真的。[1]
-
然后,我将继续为这些子部分中的每一个子部分编写解析器,并编写它们:
module Main where
import Text.Parsec
import Data.Maybe (catMaybes)
symbol :: String -> Parser String
symbol s = string s <* spaces
parens :: Parser a -> Parser a
parens = between (string "(") (string ")")
digits :: Parser Int
digits = read <$> many1 digit
parseF :: Parser F
parseF = curry F <$> firstPart <*> secondPart
where
firstPart :: Parser Int
firstPart = symbol "F" >> digits
secondPart :: Parser (Maybe String)
secondPart = optionMaybe $ choice
[ many1 letter
, parens (many1 letter)
, string "-" >> many1 alphaNum
]
-
(乔恩·珀迪在评论中写道,)
在字符串上使用此解析器获取多个匹配项,
extract :: Parser a -> Parser [a]
extract p = do (:) <$> try p <*> extract p
<|> do anyChar >> extract p
<|> do eof >> return []
readFs :: String -> Either ParseError [F]
readFs s = parse (extract parseF) "" s
main :: IO ()
main = print (readFs "F12, F 12, F1(a), F2a, F5-A, F34-5")
此打印:
Right [F (12,Nothing),F (12,Nothing),F (1,Just "a"),F (2,Just "a"),F (5,Just "A"),F (34,Just "5")]
外卖:
-
您可以使用标记解析来解析可选的空格(
symbol
)。
-
您可以使用
option
,
optionMaybe
or
optional
。
-
您可以使用
a <|> b <|> c
或
choice [a, b, c]
。
-
当在两个选项之间交替时,确保它们没有重叠的第一组。否则你需要
try
;这很令人讨厌,但有时不可避免。(在这种情况下,三个选项的第一组是
letter
,则,
string "("
和
string "-"
,即不重叠。)
[1] :为了限制,我坚持上面的假设,但我觉得我也可以假设
F1a-B
,则,
F1(a)-5
和
F1(a)-5A
有效,在这种情况下,我可能会将模型更改为:
newtype F = F (Int, Maybe String, Maybe String)
|