使用Parsec将文本删除到特殊字符

时间:2012-10-04 15:58:26

标签: haskell parsec

我是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,但我不明白如何将它们组合起来。我会感激任何简单的例子。

2 个答案:

答案 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 '%'))