2

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

4

2 回答 2

4

在编写 Parsec 代码时,首先写出要以BNF形式解析的语法很有用,因为用 Parsec 编写的解析器最终看起来非常像语法。

让我们试试:

line ::= garbage '#' field ',' field ',' field '%' garbage

在上面的产生式中,我们假设一个产生式名为garbage,其实际定义将取决于您实际想要删除的文本。同样,我们假设一个名为field. 现在让我们把这个产生式写成解析码:

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结果都会产生任何值,因为您没有将名称绑定到将被丢弃的值。

于 2012-10-04T16:31:21.613 回答
1

或者,您可以使用应用解析器:

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 '%'))
于 2012-10-04T16:49:21.010 回答