Haskell 跳过括号内的术语?
我试图使第5列中包含JSON的大型TSV文件适合导入mongoDB。 特别是,我想将顶级和仅顶级关键字段更改为_id。这是我到目前为止所做的,它似乎可以工作,但速度很慢:Haskell 跳过括号内的术语?,haskell,conduit,attoparsec,Haskell,Conduit,Attoparsec,我试图使第5列中包含JSON的大型TSV文件适合导入mongoDB。 特别是,我想将顶级和仅顶级关键字段更改为_id。这是我到目前为止所做的,它似乎可以工作,但速度很慢: {-# LANGUAGE OverloadedStrings #-} import System.Environment (getArgs) import Data.Conduit.Binary (sourceFile, sinkFile) import Data.Conduit import qualified Data.
{-# 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
{-#语言重载字符串}
导入System.Environment(getArgs)
导入Data.conductor.Binary(sourceFile,sinkFile)
导入数据。管道
将限定的Data.conductor.Text作为CT导入
导入符合条件的数据.conductor.List作为CL
导入符合条件的数据。文本为T
导入数据。Monoid(())
将Data.c.Text作为APT导入
导入控制
main=do
(inputFile:outputFile:uuu)T.Text
jsonify=go。T.splitOn“\T”
哪里
go(:::::::::::::)=大小写解析仅适用于内容的keyTo_id
右res->res“\n”
_ -> ""
go uquo
keyTo_id::解析器T.Text
keyTo_id=skipWhile(/='{')>>T.snoc
(T.cons(char'{'))
(T.concat many1(括号
(字符串“\”key\”:“>>返回“\”\u id\”:”)
APT.takeWhile1(\x->x/='{'&&x/='}'&&x/='''”)
T.singleton满足(/='}')
)))
字符'}'
括号::解析器T.Text
括号=T.cons字符'{'
扫描1测试
哪里
测试::Int->Char->Maybe Int
测试0=无
测试i'}'=Just(i-1)
测试i'{'=Just(i+1)
测试i=仅测试i
根据探查器,58.7%的时间花在括号内,19.6%花在键盘上,17.1%花在主键盘上
如果括号匹配,肯定有更好的方法返回括号内的术语不变吗
我简单地看了一下ATOPASSEC导管,但我不知道如何使用该库,甚至不知道它是否可以用于这种用途
编辑:更新了代码。数据来自openlibrary.org,例如使用
scan
函数。它允许您扫描一个保持状态的字符串。在您的情况下,状态将是一个数字-到目前为止遇到的大括号的打开和关闭的差异。
当状态为0时,这意味着大括号在当前子字符串中匹配
诀窍是,你不解构和重建字符串这种方式,所以它应该更快
此外,通过使用惰性文本,即使使用当前的算法,您也可以获得一些性能,
concat
函数将更有效地工作。我尝试了扫描,它将空间效率提高了约15%,速度提高了约5%。我不确定如何实现您的第二个建议,因为takeWhi似乎没有惰性文本版本le1或conductor.Text函数,因此我似乎必须来回转换几次。