[英]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.