如何使用Parsec否定解析器

时间:2014-09-15 02:21:40

标签: parsing haskell parsec

我有一个带有行结尾“\ 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"的反转?

3 个答案:

答案 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"
]