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

时间:2012-10-17 15:01:39

标签: haskell parsec

我正在用Parsec编写我的第一个程序。我想解析MySQL模式转储,并想提出一种很好的方法来解析表示某些关键字的字符串,不区分大小写。下面是一些代码,显示了我用来解析“CREATE”或“create”的方法。有一个更好的方法吗?不使用buildExpressionParser的答案是最好的。我在这里采取婴儿步骤。

  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

5 个答案:

答案 0 :(得分:18)

您可以使用字符解析器构建不区分大小写的解析器。

-- 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 ++ "\""

答案 1 :(得分:8)

重复我在评论中所说的内容,因为它显然很有帮助:

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

如果您在某些地方解析需要不区分大小写的内容而在其他地方需要区分大小写,或者如果您因为美观原因而关心保留大小写,则会出现明显的困难。例如,尽管HTML标记不区分大小写,但在解析它时将整个网页转换为小写可能是不合需要的。即使在编译不区分大小写的编程语言时,转换标识符也很烦人,因为任何产生的错误消息都与程序员编写的不匹配。

答案 2 :(得分:3)

不,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的作者之一。

答案 3 :(得分:0)

不要使用... <testsuites> <testsuite name="n98-magerun-tests"> <directory>./tests</directory> <exclude>tests/N98/Magento/Command/Installer/UninstallCommandTest.php</exclude> </testsuite> ... 映射整个输入,而是考虑使用toLower中的caseString(来自hsemail包)

Text.ParsecCombinators.Parsec.Rfc2234

Text.ParserCombinators.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 将是输入中存在的任何case-variant而不改变你的输入。

ps:我知道这是一个古老的问题,我只是想在我寻找类似的问题时,我会添加这个问题

答案 4 :(得分:0)

此目的有一个软件包名称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