我有一个带有行结尾“\ r \ n \ n \ n”的文件,并使用解析器eol = string "\r\r\n" :: Parser String
来处理它们。为了获得这些分隔符之间的行列表,我想使用sepBy
以及一个返回eol
无法捕获的任何文本的解析器。通过文档查看,我没有看到一个否定解析器的组合器(除了模式”\r\r\n”
'解析器之外的任何东西)。
我尝试使用sepBy (many anyToken) end
,但many anyToken
似乎很贪婪,而不是停留eol
次匹配。我无法使用many (noneOf "\n\r")
,因为我的文字中有多个地方使用单个'\n'
字符。
是否有一个组合器可以得到string "\r\r\n"
的反转?
答案 0 :(得分:7)
我害怕你倒退了。 Parsec解析器不会切断输入,他们会构建输出。 你试着通过思考你不想要的东西来解析得越多,它就会越难。你需要自下而上地思考什么是允许的,而不是在你砍掉的地方自上而下。
您应该从做想要的最小,最基本的事情开始。例如,不要将标识符视为空格之前的所有内容,将其视为字母后跟字母数字数据。然后,您可以将它与空格分开,将其与您在线上预期的其他内容分开。
line = do
i <- identifier
whiteSpace
string "="
e <- expr
return $ Line i e
只有当你完成了一个成功解析你想要的行并解析无效行的解析器时,你应该解析多行:
lines = sepBy line eol
答案 1 :(得分:3)
作为一个试探性答案,manyTill anyChar (try eol)
看起来像我想要的那样。作为我原始问题的一部分,我仍然有兴趣知道是否有一种通用的方法来否定解析器,或者是否有另一种推荐的方式来做我想要的。
答案 2 :(得分:0)
sepCap
包中的解析器组合器
replace-megaparsec
进行这种语法分析器求反,并返回Either
的列表,其中Left
中有否定匹配项,而Right
中有正则匹配项。
import Replace.Megaparsec
import Text.Megaparsec
parseTest (sepCap (chunk "\r\r\n" :: Parsec Void String String))
$ "one\r\r\ntwo\r\r\nthree\r\r\n"
[ Left "one"
, Right "\r\r\n"
, Left "two"
, Right "\r\r\n"
, Left "three"
, Right "\r\r\n"
]