使用 Text.Combinators.Parsec 进行不区分大小写解析的最干净方法是什么?



我正在用parsec编写我的第一个程序。我想解析MySQL模式转储,并想提出一种很好的方式来解析以示例敏感的方式来代表某些关键字的字符串。这是一些代码,显示我用来解析"创建"或"创建"的方法。有一个更好的方法吗?不求助于构建Expresseparser的答案是最好的。我要在这里迈出婴儿台阶。

  p_create_t :: GenParser Char st Statement
  p_create_t = do
      x <- (string "CREATE" <|> string "create")
      xs <- manyTill anyChar (char ';')
      return $ CreateTable (x ++ xs) []  -- refine later

您可以从字符解析器中构建对案例不敏感的解析器。

-- Match the lowercase or uppercase form of 'c'
caseInsensitiveChar c = char (toLower c) <|> char (toUpper c)
-- Match the string 's', accepting either lowercase or uppercase form of each character 
caseInsensitiveString s = try (mapM caseInsensitiveChar s) <?> """ ++ s ++ """

重复我在评论中说的话,因为这显然很有帮助:

这里简单的大锤解决方案是在运行解析器之前简单地在整个输入上映射toLower,然后在小写中进行所有关键字匹配。

,如果您要解析某些地方需要对病例不敏感的东西,而在其他地方则呈敏感,或者出于化妆品的原因保存案例,这会带来明显的困难。例如,尽管HTML标签是对病例敏感的,将整个网页转换为小写,而解析可能是不希望的。即使编译了对案例不敏感的编程语言,转换标识符也可能很烦人,因为任何结果的错误消息都不匹配程序员所写的内容。

不,parsec不能以干净的方式做string在原始的tokens组合器,用于使用平等测试很难编码 (==)。解析案例不敏感的角色有点简单,但是您可能想要更多。

然而,有一个现代的parsec叉,称为具有Megaparsec内置解决方案适用于您想要的一切:

λ> parseTest (char' 'a') "b"
parse error at line 1, column 1:
unexpected 'b'
expecting 'A' or 'a'
λ> parseTest (string' "foo") "Foo"
"Foo"
λ> parseTest (string' "foo") "FOO"
"FOO"
λ> parseTest (string' "foo") "fo!"
parse error at line 1, column 1:
unexpected "fo!"
expecting "foo"

请注意最后一个错误消息,它比您可以解析的要好字符一一(在您的特定情况下特别有用)。string'就像Parsec的string一样实现,但使用不敏感的比较比较字符。还有oneOf'noneOf'在某些情况下可能会有所帮助。


披露:我是Megaparsec的作者之一。

而不是用toLower映射整个输入,而是考虑使用Text.ParserCombinators.Parsec.Rfc2234(来自HSemail软件包)的caseString

text.parseccombinators.parsec.rfc2234

p_create_t :: GenParser Char st Statement
p_create_t = do
  x <- (caseString "create")
  xs <- manyTill anyChar (char ';')
  return $ CreateTable (x ++ xs) []  -- refine later

因此,现在x将是输入中存在的情况变化而不更改输入。

ps:我知道这是一个古老的问题,我只是以为我会添加这个问题,因为我在寻找类似问题的时候出现了这个问题

为此目的有一个包装名称parsec-extra。您需要安装此软件包,然后使用' caseinsensitivestring '解析器。

 :m Text.Parsec
 :m +Text.Parsec.Extra
*> parseTest   (caseInsensitiveString  "values")   "vaLUES"
"values"
*> parseTest   (caseInsensitiveString  "values")   "VAlues"
"values"

链接到包装在这里:https://hackage.haskell.org/package/parsec-extra

最新更新