使用Attoparsec时输入不完整的问题

时间:2010-06-07 11:22:03

标签: haskell attoparsec

我正在转换使用Parsec的一些功能正常的Haskell代码,而不是使用Attoparsec以期获得更好的性能。我做了更改,所有内容都编译但我的解析器无法正常工作。

我正在解析一个由各种记录类型组成的文件,每行一个。我用于解析记录或注释的每个函数都能正常工作,但是当我尝试编写一个函数来编译一系列记录时,解析器总是会返回一个部分结果,因为它需要更多的输入。

这是我尝试过的两个主要变体。两者都有同样的问题。

items :: Parser [Item]
items = sepBy (comment <|> recordType1 <|> recordType2) endOfLine

对于第二个,我更改了记录/评论解析器以使用行尾字符。

items :: Parser [Item]
items = manyTill (comment <|> recordType1 <|> recordType2) endOfInput

我的方法有什么问题吗?还有其他方法可以实现我的目标吗?

3 个答案:

答案 0 :(得分:5)

如果编写一个attoparsec解析器,在失败之前消耗尽可能多的输入,则必须在输入结束时告知部分结果延续。

答案 1 :(得分:3)

之前我遇到过这个问题,我的理解是<|>sepBy定义中的作用方式引起的:

sepBy1 :: Alternative f => f a -> f s -> f [a]
sepBy1 p s = scan
    where scan = liftA2 (:) p ((s *> scan) <|> pure [])

一旦pure []失败,这只会转移到(s *> scan),这不会因为你在输入结束时发生。

我的解决方案就是在feed返回的empty上使用Result ByteString调用parse。这可能是一种黑客攻击,但它似乎也是attoparsec-iteratee处理问题的方式:

f k (EOF Nothing)  = finalChunk $ feed (k S.empty) S.empty

据我所知,这是attoparsec-iteratee在这里工作而普通老parse没有的唯一原因。

答案 2 :(得分:0)

你提供的信息很少,这就是为什么我觉得很难给你很好的帮助。但是我想提出几点意见:

  • 也许解析器没有意识到输入已经完成,它取决于获得EOL还是获得另一条记录。因此它要求部分结果。尝试喂它相当于EOL,希望它强制它。
  • 我记不起代码,但使用Alternative实例可能对解析性能不利。如果是这种情况,您可能需要注释comment和recordTypes。
  • 我使用谷物进行大量的二元分析,这也非常快。 attoparsec看起来更像是一个文本解析器。你一定要考虑这个选择。
  • 另一种选择是在较长时间内使用基于iteratee的IO。 John Lato在最新的monad读者中发表了一篇关于iteratees的精彩文章(我相信第16期)。行尾条件是要发信号的迭代。请注意,迭代类型非常令人生畏,需要一些时间习惯。