haskell - 秒差距非贪婪重复

标签 haskell parsec non-greedy

我试图将我的输入分成与特定模式匹配的部分和其余部分,比方说

data Data = A Int | B Char | C String
parseDatas :: Parsec [Token] () a [Data]

我已经编写了两个或多或少复杂的解析器

parseA :: Parsec [Token] () Data
parseB :: Parsec [Token] () Data

与我正在寻找的东西相匹配。现在显而易见的解决方案是

parseDatas = many (parseA <|> parseB <|> parseC)

中间部分的解析器如下所示:

makeC :: [Token] -> Data
makeC = C . concatMap show -- or something like this
parseC :: Parsec [Token] () Data
parseC = makeC <$> many anyToken

嗯,这会引发运行时[ERROR] Text.ParserCombinators.Parsec.Prim.many:组合器“many”应用于接受空字符串的解析器。 - 好的,很容易修复:

parseC = makeC <$> many1 anyToken

但是现在 parseC 消耗整个输入(以我不寻找的内容开头),忽略任何应该产生 AB 的模式!

如果我的模式是正则表达式1,我现在会将 + 运算符更改为非贪婪 +? 运算符。如何对 many1 解析器组合器执行相同操作?

1:我无法使用它,因为我正在操作 token 而不是字符


我找到的解决方案是

parseC = makeC <$> many1 (notFollowedBy (parseA <|> parseB) >> anyToken)

但这看起来确实,呃,不太理想。这并不是很通用。一定有更好的东西。

我还查看了Parsec how to find "matches" within a string其中建议是定义一个递归解析器,但如果我不想删除中间标记并将它们收集在列表中,这看起来会很困惑。

最佳答案

您可以让 parseC 一次只消耗一个 token :

parseDatas = many $ parseA <|> parseB <|> (C . show <$> anyToken)

然后,如果需要,将相邻的 C 分组s 合二为一以保存语义:

groupCs (C c) (C c':xs) = C (c ++ c') : xs
groupCs x xs = x : xs
parseDatas = foldr groupCs [] <$> many (parseA <|> parseB <|> (C . show <$> anyToken))

如果你想应用一些操作make :: [Token] -> String连续 C s:

data Data c = A Int | B Char | C c deriving Functor

groupCs :: [Data a] -> [Data [a]] -> [Data [a]]
groupCs (C c) (C cs:xs) = C (c:cs) : xs
groupCs (C c) xs = C [c] : xs
groupCs x xs = x : xs

parseDatas = (map.fmap) make . foldr groupCs [] <$> many (parseA <|> parseB <|> (C <$> anyToken))

关于haskell - 秒差距非贪婪重复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38762263/

相关文章:

regex - 贪婪/懒惰(非贪婪)/占有量词如何在内部工作?

haskell - 如何在 Haskell 中实现最佳优先搜索?

exception - 定义和捕获异常

regex - 如何编写非贪婪匹配的正则表达式?

haskell - 使用 Haskell 的 Parsec 解析 float

javascript - 非贪婪地隔 ionic 字符串?

xml - HXT上的错误系统

haskell - 将 monad 添加到变压器堆栈的中间

haskell - 秒差距输入错误