【问题标题】:Attoparsec: Skipping bracketed terms?Attoparsec:跳过括号中的术语?
【发布时间】:2012-10-03 16:03:33
【问题描述】:

我正在尝试在第 5 列中使用 JSON 制作适合导入 mongoDB 的大型 TSV 文件。 特别是我想将顶级且仅顶级关键字段更改为_id。这是我到目前为止所拥有的,它似乎工作但很慢:

{-# LANGUAGE OverloadedStrings #-}

import System.Environment (getArgs)
import Data.Conduit.Binary (sourceFile, sinkFile)
import Data.Conduit
import qualified Data.Conduit.Text as CT
import qualified Data.Conduit.List as CL
import qualified Data.Text as T
import Data.Monoid ((<>))
import Data.Attoparsec.Text as APT
import Control.Applicative

main = do 
        (inputFile : outputFile : _) <- getArgs
        runResourceT $ sourceFile inputFile  
                $= CT.decode CT.utf8 $= CT.lines $= CL.map jsonify 
                $= CT.encode CT.utf8 $$ sinkFile outputFile

jsonify :: T.Text -> T.Text
jsonify = go . T.splitOn "\t"
        where 
        go (_ : _ : _ : _ : content : _) = case parseOnly keyTo_id content of
                Right res -> res <> "\n"
                _ -> ""
        go _ = ""

keyTo_id :: Parser T.Text 
keyTo_id = skipWhile(/='{') >> T.snoc <$>
        (T.cons <$> (char '{') 
                <*> (T.concat <$> many1 ( bracket 
                    <|> (string "\"key\":" >> return "\"_id\":") 
                    <|> APT.takeWhile1(\x -> x /= '{' && x /= '}' && x/= '"') 
                    <|> T.singleton <$> satisfy (/= '}')
                    )))  
        <*> char '}'        

bracket :: Parser T.Text        
bracket = T.cons <$> char '{' 
        <*> scan 1 test
     where
        test :: Int -> Char -> Maybe Int
        test 0 _ = Nothing        
        test i  '}'= Just (i-1)
        test i '{' = Just (i+1)
        test i _ = Just i

根据分析器,58.7% 的时间花在括号中,19.6% 用于 keyTo_id,17.1% 用于 main。

如果括号匹配,肯定有更好的方法来返回括号中的术语吗?

我简要地查看了 attoparsec-conduit,但我不知道如何使用该库,甚至无法判断这是否是它可以用来做的事情。

编辑:更新了代码。数据来自 openlibrary.org,e。 G。 http://openlibrary.org/data/ol_dump_authors_latest.txt.gz

【问题讨论】:

    标签: haskell conduit attoparsec


    【解决方案1】:

    使用scan 函数。它允许您扫描维护状态的字符串。在您的情况下,状态将是一个数字——到目前为止您遇到的左大括号和右大括号的区别。 当您的状态为 0 时,这意味着大括号匹配当前子字符串。

    诀窍是你不要以这种方式解构和重构字符串,所以它应该更快。

    此外,即使使用当前算法,您也可以通过使用惰性文本获得一些性能 - concat 函数会更有效地工作。

    【讨论】:

    • 我试过扫描,它提高了大约 15% 的空间效率和大约 5% 的速度。我不确定如何实施您的第二个建议,因为似乎没有 takeWhile1 或 Conduit.Text 函数的惰性文本版本,所以看来我必须来回转换几次。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-26
    • 2012-04-23
    • 1970-01-01
    • 2020-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多