我使用 attoparsec
编写了以下解析代码:
data Test = Test {
a :: Int,
b :: Int
} deriving (Show)
testParser :: Parser Test
testParser = do
a <- decimal
tab
b <- decimal
return $ Test a b
tParser :: Parser [Test]
tParser = many' $ testParser <* endOfLine
这适用于小文件,我是这样执行的:
main :: IO ()
main = do
text <- TL.readFile "./testFile"
let (Right a) = parseOnly (manyTill anyChar endOfLine *> tParser) text
print a
但是当文件大小大于 70MB 时,它会消耗大量内存。作为解决方案,我想我会使用
attoparsec-conduit
.经过他们的API ,我不知道如何让它们一起工作。我的解析器的类型是 Parser Test
但它是 sinkParser
实际上接受 Parser a b
类型的解析器.我对如何在常量内存中执行这个解析器感兴趣? (基于管道的解决方案也是可以接受的,但我不习惯管道 API。)
最佳答案
Parser
的第一个类型参数只是输入的数据类型( Text
或 ByteString
)。您可以提供您的 testParser
函数作为 sinkParser
的参数它会正常工作。这是一个简短的例子:
{-# LANGUAGE OverloadedStrings #-}
import Conduit (liftIO, mapM_C, runResourceT,
sourceFile, ($$), (=$))
import Data.Attoparsec.Text (Parser, decimal, endOfLine, space)
import Data.Conduit.Attoparsec (conduitParser)
data Test = Test {
a :: Int,
b :: Int
} deriving (Show)
testParser :: Parser Test
testParser = do
a <- decimal
space
b <- decimal
endOfLine
return $ Test a b
main :: IO ()
main = runResourceT
$ sourceFile "foo.txt"
$$ conduitParser testParser
=$ mapM_C (liftIO . print)
关于parsing - 将普通的 attoparsec 解析器代码转换为基于管道/管道的代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24058882/