簡體   English   中英

管道中的“子解析器” - attoparsec

[英]“Sub-parsers” in pipes-attoparsec

我正在嘗試使用Haskell中的pipes-attoparsec解析二進制數據。 管道(代理)涉及的原因是將讀取與解析交錯以避免大文件的高內存使用。 許多二進制格式基於塊(或塊),它們的大小通常由文件中的字段描述。 我不確定這個塊的解析器是什么被調用,但這就是我所說的標題中的“sub-parser”。 我遇到的問題是以簡潔的方式實現它們而沒有可能很大的內存占用。 我想出了兩個在某些方面都失敗的替代方案。

備選方案1是將塊讀入單獨的字節串並為其啟動單獨的解析器。 簡潔,大塊將導致高內存使用。

備選方案2是在相同的上下文中保持解析並跟蹤消耗的字節數。 這種跟蹤容易出錯,並且似乎會影響組成最終blockParser的所有解析器。 對於格式錯誤的輸入文件,在比較跟蹤大小之前,還可以通過進一步解析比大小字段所指示的方式來浪費時間。

import Control.Proxy.Attoparsec
import Control.Proxy.Trans.Either
import Data.Attoparsec as P
import Data.Attoparsec.Binary
import qualified Data.ByteString as BS

parser = do
    size <- fromIntegral <$> anyWord32le

    -- alternative 1 (ignore the Either for simplicity):
    Right result <- parseOnly blockParser <$> P.take size
    return result

    -- alternative 2
    (result, trackedSize) <- blockparser
    when (size /= trackedSize) $ fail "size mismatch"
    return result

blockParser = undefined

main = withBinaryFile "bin" ReadMode go where
    go h = fmap print . runProxy . runEitherK $ session h
    session h = printD <-< parserD parser <-< throwParsingErrors <-< parserInputD <-< readChunk h 128
    readChunk h n () = runIdentityP go where
        go = do
            c <- lift $ BS.hGet h n
            unless (BS.null c) $ respond c *> go

我喜歡稱之為“固定輸入”解析器。

我可以告訴你pipes-parse將如何做到這一點。 您可以在庫的parseNparseWhile函數中看到我將要在pipes-parse的內容的parseN 這些實際上是用於通用輸入,但我在這里這里也寫了類似的String解析器。

訣竅很簡單,你在輸入標記的末端插入一個你希望解析器停止的地方,運行解析器(如果遇到輸入標記的假端則會失敗),然后刪除輸入標記的結尾。

顯然,這並不像我說的那么容易,但這是一般原則。 棘手的部分是:

  • 這樣做仍然會流動。 我鏈接的那個並沒有這樣做,但是,你以流式方式執行此操作的方法是在上游插入一個管道,計算流經它的字節,然后將輸入結束標記插入正確的位置。

  • 不干擾輸入標記的現有結束

這個技巧可以適用於pipes-attoparsec ,但我認為最好的解決辦法是讓attoparsec直接包含這個功能。 但是,如果該解決方案不可用,那么我們可以限制輸入到attoparsec解析器的輸入。

好的,所以我終於想出了如何做到這一點,並且我已經在pipes-parse庫中編寫了這個模式。 pipes-parse教程解釋了如何執行此操作,特別是在“嵌套”部分中。

本教程僅解釋了這種與數據類型無關的解析(即通用的元素流),但您也可以將其擴展為與ByteString一起使用。

使這項工作的兩個關鍵技巧是:

  • StateP修復為全局(在pipes-3.3.0

  • 將子解析器嵌入到瞬態StateP層中,以便它使用新的剩余上下文

pipes-attoparsec將很快發布一個基於pipes-parse的更新,以便您可以在自己的代碼中使用這些技巧。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM