我是Haskell和Parsec的新手 - 如果这个问题很简单,我很抱歉。
我想解析结构如下的文本行:
<Text to be dropped> <special character (say "#")> <field 1> <comma> <field 2>
<comma> <field 3> <special character 2 (say "%")> <Text to be dropped>
我希望我的解析器在开头和结尾丢弃“要删除的文本”,并且 保留字段的内容。我的主要问题是理解如何编写一个解析器,将所有内容都丢弃到某个特殊字符。
来自库的解析器看起来很有帮助的是anyChar,manyTill和oneOf,但我不明白如何将它们组合起来。我会感激任何简单的例子。
答案 0 :(得分:3)
在编写Parsec代码时,首先写出要以BNF形式解析的语法是有用的,因为用Parsec编写的解析器最终看起来像语法。
我们试试看:
line ::= garbage '#' field ',' field ',' field '%' garbage
在上面的制作中,我们假设一个名为garbage
的作品,其实际定义将取决于您实际想要删除的文本。同样,我们假设一个名为field
的产品。现在让我们把这个产品写成parsec代码:
line = do
garbage
char '#'
field1 <- field
char ','
field2 <- field
char ','
field3 <- field
char '%'
garbage
return (field1, field2, field3)
此代码与BNF完全相同。本质区别在于某些子产品的结果已命名,因此我们可以返回根据这些结果构建的值(在本例中为元组)。
现在我不知道你的垃圾概念是什么,但为了举例,让我们假设你的意思是任何空格。然后,您可以按如下方式定义garbage
:
garbage = many space
(或者,parsec已经有一个用于解析零个或多个名为spaces
的空格的组合子。如果垃圾可以是除#
分隔符之外的任何内容,那么你可以说
garbage = many (noneOf "#")
此行将删除所有输入,直到排除第一个'#'。无论哪种方式,无论值garbage
产生什么值,因为您没有将名称绑定到该值,它将被丢弃。
答案 1 :(得分:1)
或者,您可以使用applicative parsers:
import Control.Applicative
import Text.Parsec
import Text.Parsec.String
type Field = () --your type here
field = string "()" *> pure () --your parser here
parser :: Parser (Field, Field, Field)
parser = manyTill anyChar (char '#') *>
((,,) <$> (field <* char ',')
<*> (field <* char ',')
<*> (field <* char '%'))