簡體   English   中英

在管道中跳過第一行 - attoparsec

[英]Skipping first line in pipes-attoparsec

我的類型:

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

有什么想法來解決這個問題嗎?

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

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

在此之后,您可以使用Pipes.Prelude提供的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)

您可以在常量空間中有效地刪除第一行,如下所示:

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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM