[英]Haskell attoparsec: “Failed reading: satisfyWith”
我想將"John","Kate","Ruddiger"
等文本解析為字符串列表。
我試着從解析"John",
到Name(String的別名)開始,但它已經失敗, Fail "\\"," [","] "Failed reading: satisfyWith"
。
問題A:為什么會出現此錯誤,如何解決? (我沒有在attoparsec的源代碼中找到滿意的調用)
問題B:如何使解析器在姓氏后不需要逗號?
{-# LANGUAGE OverloadedStrings #-}
import Data.Attoparsec.Char8 as P
import qualified Data.ByteString.Char8 as BS
import Control.Applicative(many)
data Name = Name String deriving Show
readName = P.takeWhile (/='"')
entryParser :: Parser Name
entryParser = do
P.char '"'
name <- readName
P.char ','
return $ Name (BS.unpack name)
someEntry :: IO BS.ByteString
someEntry = do
return $ BS.pack "\"John\","
main :: IO()
main = do
someEntry >>= print . parse entryParser
我使用的是GHC 7.6.3和attoparsec-0.11.3.4。
問題A:為什么會出現此錯誤,如何解決? (我沒有在attoparsec的源代碼中找到滿意的調用)
readName = P.takeWhile (/='"')
只要謂詞為真, takeWhile
消耗takeWhile
。 為此,你讀的名稱后, "
。沒有被消耗掉這是很容易看到,如果我們去掉P.char ','
從entryParser
:
entryParser = P.char '"' >> fmap (Name . BS.unpack) readName
$ runhaskell SO.hs Done "\"," Name "John"
你需要消費"
:
entryParser :: Parser Name
entryParser = do
P.char '"'
name <- readName
P.char '"' -- <<<<<<<<<<<<<<<<<<<<<<
P.char ','
return $ Name (BS.unpack name)
問題B:如何使解析器在姓氏后不需要逗號?
使用sepBy
。
現在你的問題已經解決了,讓事情變得更容易一些。 不消耗,
在所有entryParser
,而不是只取名字:
entryParser = P.char '"' *> fmap ( Name . BS.unpack ) readName <* P.char '"'
如果您不知道(*>)
和(<*)
,它們都來自Control.Applicative
,它們基本上意味着“丟棄星號側的任何內容”。
現在,為了解析所有逗號分隔的條目,我們使用sepBy entryParser (P.char ',')
。 但是,這會導致attoparsec返回Partial:
$ runhaskell SO.hs Partial _
這實際上是attoparsec的一個特點,你必須記住:
Attoparsec支持增量輸入,這意味着您可以為其提供一個字節字符串,該字符串僅表示要解析的預期數據總量的一部分。 如果您的解析器到達輸入片段的末尾並且可能消耗更多輸入,它將暫停解析並返回
Partial
延續。
如果您確實想使用增量輸入,請使用parse
和feed
。 否則使用parseOnly
。 您的示例的完整代碼將是類似的
{-# LANGUAGE OverloadedStrings #-}
import Data.Attoparsec.Char8 as P
import qualified Data.ByteString.Char8 as BS
import Control.Applicative(many, (*>), (<*))
data Name = Name String deriving Show
readName = P.takeWhile (/='"')
entryParser :: Parser Name
entryParser = P.char '"' *> fmap ( Name . BS.unpack ) readName <* P.char '"'
allEntriesParser = sepBy entryParser (P.char ',')
testString = "\"John\",\"Martha\",\"test\""
main = print . parseOnly allEntriesParser $ testString
$ runhaskell SO.hs Right [Name "John",Name "Martha",Name "test"]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.