Sib*_*ibi 4 haskell attoparsec haskell-pipes
我的类型:
data Test = Test {
a :: Int,
b :: Int
} deriving (Show)
Run Code Online (Sandbox Code Playgroud)
我的解析器:
testParser :: Parser Test
testParser = do
a <- decimal
tab
b <- decimal
return $ Test a b
tab = char '\t'
Run Code Online (Sandbox Code Playgroud)
现在为了跳过第一行,我做了这样的事情:
import qualified System.IO as IO
parser :: Parser Test
parser = manyTill anyChar endOfLine *> testParser
main = IO.withFile testFile IO.ReadMode $ \testHandle -> runEffect $
for (parsed (parser <* endOfLine) (fromHandle testHandle)) (lift . print)
Run Code Online (Sandbox Code Playgroud)
但是上面的parser
函数会使每个备用链接跳过(很明显).如何以与Pipes生态系统一起工作的方式跳过第一行(Producer
应该产生单个Test
值.)这是一个我不想要的明显解决方案(下面的代码只有在我修改testParser读取换行符时才有效)因为它返回整个[Test]
而不是单个值:
tests :: Parser [Test]
tests = manyTill anyChar endOfLine *>
many1 testParser
Run Code Online (Sandbox Code Playgroud)
有什么想法来解决这个问题吗?
如果第一行不包含任何有效Test
,您可以使用Either () Test
它来处理它:
parserEither :: Parser (Either () Test)
parserEither = Right <$> testParser <* endOfLine
<|> Left <$> (manyTill anyChar endOfLine *> pure ())
Run Code Online (Sandbox Code Playgroud)
在此之后,您可以使用提供的函数Pipes.Prelude
来删除第一个结果(以及所有不可解析的行):
producer p = parsed parserEither p
>-> P.drop 1
>-> P.filter (either (const False) (const True))
>-> P.map (\(Right x) -> x)
main = IO.withFile testFile IO.ReadMode $ \testHandle -> runEffect $
for (producer (fromHandle testHandle)) (lift . print)
Run Code Online (Sandbox Code Playgroud)
您可以在常量空间中有效地删除第一行,如下所示:
import Lens.Family (over)
import Pipes.Group (drops)
import Pipes.ByteString (lines)
import Prelude hiding (lines)
dropLine :: Monad m => Producer ByteString m r -> Producer ByteString m r
dropLine = over lines (drops 1)
Run Code Online (Sandbox Code Playgroud)
您可以应用dropLine
到你的Producer
,你解析之前Producer
,就像这样:
main = IO.withFile testFile IO.ReadMode $ \testHandle -> runEffect $
let p = dropLine (fromHandle testHandle)
for (parsed (parser <* endOfLine) p) (lift . print)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
244 次 |
最近记录: |