【问题标题】:Skipping first line in pipes-attoparsec跳过管道中的第一行 - attoparsec
【发布时间】:2014-07-10 10:16:05
【问题描述】:

我的类型:

data Test = Test {
 a :: Int,
 b :: Int
} deriving (Show)

我的解析器:

testParser :: Parser Test
testParser = do
  a <- decimal
  tab
  b <- decimal
  return $ Test a b

tab = char '\t'

现在为了跳过第一行,我做了这样的事情:

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)

但上面的parser 函数会跳过每个备用链接(这很明显)。如何仅以与 Pipes 生态系统一起使用的方式跳过第一行(Producer 应该产生单个 Test 值。)这是我不想要的一个明显的解决方案(下面的代码仅在以下情况下才有效我修改 testParser 以读取换行符)因为它返回整个 [Test] 而不是单个值:

tests :: Parser [Test]
tests = manyTill anyChar endOfLine *>
        many1 testParser

有解决这个问题的想法吗?

【问题讨论】:

  • 顺便说一下,你在TestLink之间切换。
  • @Zeta 抱歉,这是我的错误。更新为Test。 (我原来的数据结构实际上是Link,它有更多的字段。我只是为了这个问题将它简化为Test。)

标签: haskell attoparsec haskell-pipes


【解决方案1】:

您可以像这样在恒定空间中有效地删除第一行:

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)

您可以在解析Producer 之前将dropLine 应用于您的Producer,如下所示:

main = IO.withFile testFile IO.ReadMode $ \testHandle -> runEffect $
    let p = dropLine (fromHandle testHandle)
    for (parsed (parser <* endOfLine) p) (lift . print)

【讨论】:

  • 什么是不想掉线,只是等待线?有没有比over lines (drops o)更好的方法?
  • @Igor 除了Pipes.Preludepipes 生态系统不鼓励将整行读入内存,因为它们可能是任意长的。要了解如何以惯用方式执行此操作,请研究 Pipes.Group tutorial 并查看 Pipes.Text.lines
【解决方案2】:

如果第一行不包含任何有效的Test,您可以使用Either () Test 来处理它:

parserEither :: Parser (Either () Test)
parserEither = Right <$> testParser <* endOfLine 
           <|> Left <$> (manyTill anyChar endOfLine *> pure ())

在此之后,您可以使用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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-15
    • 1970-01-01
    • 1970-01-01
    • 2014-06-07
    • 2013-08-17
    相关资源
    最近更新 更多