ATTOPARSEC : 브래킷을 건너 뛴 용어?
-
13-12-2019 - |
문제
나는 몽고브로 가져 오기에 적합한 5 번째 칼럼에서 JSON으로 큰 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
.
Profiler 58.7 %에 따르면 Bracket에서 keyto_id에서 19.6 %, 주요 17.1 %.
괄호가 일치하면 브래킷이 일치하면 브래킷이없는 용어를 변경하지 않는 더 나은 방법이 있습니다.
나는 Attoparsec-conduit를 간략하게 보았지만 해당 도서관을 사용하는 방법을 모르며 이것이 사용될 수있는 일종의 일을 알 수 없습니다.
편집 : 코드를 업데이트했습니다.데이터는 OpenLibrary.org, e.지. http:///openlibrary.org/data/ol_dump_authors_latest.txt.gz
해결책
scan
기능을 사용하십시오.상태를 유지하는 문자열을 스캔 할 수 있습니다.귀하의 경우 주정부는 지금까지 발생한 개폐 중괄호의 차이입니다.
귀하의 상태가 0 일 때, 그것은 중괄호가 현재 하위 문자열 내부에서 일치 함을 의미합니다.
트릭은이 방법으로 문자열을 해체하고 재구성하지 않으므로 더 빨라야한다는 것입니다.
또한 게으른 텍스트를 사용하여 현재 알고리즘을 사용하여 일부 성능을 얻을 수 있습니다. concat
기능이보다 효율적으로 작동합니다.
제휴하지 않습니다 StackOverflow