haskell - 当输入大于缓冲区大小时 attoparsec-iteratee 不起作用

标签 haskell iterate attoparsec

我有一个简单的基于 attoparsec 的 pdf parser .它工作正常,直到与 iteratee 一起使用。
当输入的大小超过缓冲区大小时。

import qualified Data.ByteString as BS
import qualified Data.Iteratee as I
import qualified Data.Attoparsec as P
import qualified Data.Attoparsec.Iteratee as P
import System.Environment (getArgs)
import Control.Monad

import Pdf.Parser.Value

main :: IO ()
main = do
  [i] <- getArgs
  liftM (P.parseOnly parseValue) (BS.readFile i) >>= print  -- works
  I.fileDriverRandomVBuf 2048 (P.parserToIteratee parseValue) i >>= print  -- works
  I.fileDriverRandomVBuf 1024 (P.parserToIteratee parseValue) i >>= print  -- DOES NOT works!!!

输入:
<< /Annots [ 404 0 R 547 0 R ] /ArtBox [ 0.000000 0.000000 612.000000 792.000000 ] /BleedBox [ 0.000000 0.000000 612.000000 792.000000 ] /Contents [ 435 0 R 436 0 R 437 0 R 444 0 R 448 0 R 449 0 R 450 0 R 453 0 R ] /CropBox [ 0.000000 0.000000 612.000000 792.000000 ] /Group 544 0 R /MediaBox [ 0.000000 0.000000 612.000000 792.000000 ] /Parent 239 0 R /Resources << /ColorSpace << /CS0 427 0 R /CS1 427 0 R /CS2 428 0 R >> /ExtGState << /GS0 430 0 R /GS1 431 0 R /GS2 469 0 R /GS3 475 0 R /GS4 439 0 R /GS5 480 0 R /GS6 485 0 R /GS7 491 0 R /GS8 497 0 R >> /Font << /C2_0 447 0 R /T1_0 421 0 R /T1_1 422 0 R /T1_2 423 0 R /T1_3 424 0 R /T1_4 425 0 R /T1_5 426 0 R /T1_6 438 0 R >> /ProcSet [ /PDF /Text /ImageC /ImageI ] /Properties << /MC0 << /Metadata 502 0 R >> >> /XObject << /Fm0 451 0 R /Fm1 504 0 R /Fm2 513 0 R /Fm3 515 0 R /Fm4 517 0 R /Fm5 526 0 R /Fm6 528 0 R /Fm7 537 0 R /Fm8 539 0 R /Im0 540 0 R /Im1 541 0 R /Im2 452 0 R /Im3 542 0 R /Im4 543 0 R >> >> /Rotate 0 /StructParents 1 /TrimBox [ 0.000000 0.000000 612.000000 792.000000 ] /Type /Page >>

因此,解析器在没有 iteratee 的情况下工作,处理足够大的块,但不适用于较小的块。迭代中的错误?在 attoparsec-iteratee 中?在我的代码中?有什么解决方法吗?这对我来说是一个非常紧迫的问题。

谢谢。

最佳答案

编辑 2:我在 Pdf/Parser/Value 中创建了一个新的解析器

dictOrStream :: Parser PdfValue
dictOrStream = do
  dict <- parseDict
  P.skipSpace
  let s1 = do
            P.string $ fromString "stream"
            content <- P.manyTill P.anyWord8 $ P.endOfLine >> P.string (fromString "endstream")
            return $ PdfValStream (PdfStream dict (BS.pack content))
  s1 <|> return (PdfValDict dict)

然后在 parseValue 中使用了这个解析器.这适用于您的所有情况。不知道为什么choice无法正确回溯,也许是 attoparsec 错误?

编辑:我注意到,如果我替换您的顶级 parseValueparseDict , 有用。如果我删除 parseStream,它也有效来自 parseValue 中的选择.我认为 attoparsec 在顶级字典完成后已 promise 使用“parseStream”,因此它期望更多的输入(空格、“stream”标记等)导致此错误。此时,您需要解决这两个解析选项之间的歧义。当整个输入可用时,我不知道为什么它可以正常工作;我希望当您的解析器被提供块时会报告错误。

到目前为止,我怀疑您的代码或 attoparsec 中存在错误。我通过手动读取字节串块并将其提供给您的 attoparsec 解析器来运行以下测试:
*Main System.IO> h <- openFile "test.pdf" ReadMode
*Main System.IO Data.ByteString> let hget = hGetSome h 1024
*Main System.IO Data.ByteString> b <- hget
*Main System.IO Data.ByteString> let r = P.parse parseValue b
*Main System.IO Data.ByteString> r
Partial _
*Main System.IO Data.ByteString> b <- hget
*Main System.IO Data.ByteString> let r' = P.feed r b
*Main System.IO Data.ByteString> r'
Partial _
*Main System.IO Data.ByteString> b <- hget
*Main System.IO Data.ByteString> Data.ByteString.length b
0
*Main System.IO Data.ByteString> let r'2 = P.feed r' b
*Main System.IO Data.ByteString> r'2
Fail "<< /Annots [ 404 0 R 547 0 R ] /ArtBox [ 0.000000 0.000000 612.000000 792.000000 ] /BleedBox [ 0.000000 0.000000 612.000000 792.000000 ] /Contents [ 435 0 R 436 0 R 437 0 R 444 0 R 448 0 R 449 0 R 450 0 R 453 0 R ] /CropBox [ 0.000000 0.000000 612.000000 792.000000 ] /Group 544 0 R /MediaBox [ 0.000000 0.000000 612.000000 792.000000 ] /Parent 239 0 R /Resources << /ColorSpace << /CS0 427 0 R /CS1 427 0 R /CS2 428 0 R >> /ExtGState << /GS0 430 0 R /GS1 431 0 R /GS2 469 0 R /GS3 475 0 R /GS4 439 0 R /GS5 480 0 R /GS6 485 0 R /GS7 491 0 R /GS8 497 0 R >> /Font << /C2_0 447 0 R /T1_0 421 0 R /T1_1 422 0 R /T1_2 423 0 R /T1_3 424 0 R /T1_4 425 0 R /T1_5 426 0 R /T1_6 438 0 R >> /ProcSet [ /PDF /Text /ImageC /ImageI ] /Properties << /MC0 << /Metadata 502 0 R >> >> /XObject << /Fm0 451 0 R /Fm1 504 0 R /Fm2 513 0 R /Fm3 515 0 R /Fm4 517 0 R /Fm5 526 0 R /Fm6 528 0 R /Fm7 537 0 R /Fm8 539 0 R /Im0 540 0 R /Im1 541 0 R /Im2 452 0 R /Im3 542 0 R /Im4 543 0 R >> >> /Rotate 0 /StructParents 1 /TrimBox [ 0.000000 0.000000" [] "Failed reading: empty"

出于某种原因,您的解析器似乎不喜欢以块的形式接收数据,并且在接收到第三个(空)块时失败而不消耗任何输入。我还没有弄清楚你的解析器哪里出错了,但它绝对不是 iteratee 或 attoparsec-iteratee。

关于haskell - 当输入大于缓冲区大小时 attoparsec-iteratee 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8995622/

相关文章:

haskell - 在haskell中解析Karva符号

haskell - 管道:产生内存泄漏

haskell - 用于转换为有界积分的 Prism

haskell - 请求澄清 McBride/Paterson Applicative 论文中的转置示例

haskell - 可变参数列表构造函数,如何默认为正确的类型并获得类型安全

haskell - State 的仿函数实例

java - Play Framework 2.2 Java Iteratee - 响应式上传

scala - Play Framework 2.0 BodyParser - 推送解析 XML 流