这个简单的解析器应该解析格式为
的消息key: value\r\nkey: value\r\n\r\nkey: value\r\nkey: value\r\n\r\n
一个EOL充当字段分隔符,双EOL充当消息分隔符。当EOL分隔符为\n
但parseWith
始终在\r\n
时返回失败时,它完全正常。
parsePair = do
key <- B8.takeTill (==':')
_ <- B8.char ':'
_ <- B8.char ' '
value <- B8.manyTill B8.anyChar endOfLine
return (key, value)
parseListPairs = sepBy parsePair endOfLine <* endOfLine
parseMsg = sepBy parseListPairs endOfLine <* endOfLine
答案 0 :(得分:3)
我假设您正在使用这些导入:
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.Attoparsec.ByteString.Char8 as B8
import Data.Attoparsec.ByteString.Char8
问题是endOfLine
消耗了行尾,所以也许你真的想要这样的东西:
parseListPairs = B8.many1 parsePair <* endOfInput
例如,这有效:
ghci> parseOnly parseListPairs "k: v\r\nk2: v2\r\n"
Right [("k","v"),("k2","v2")]
更新
要解析多条消息,您可以使用:
parseListPairs = B8.manyTill parsePair endOfLine
parseMsgs = B8.manyTill parseListPairs endOfInput
ghci> test3 = parseOnly parseMsgs "k1: v1\r\nk2: v2\r\n\r\nk3: v3\r\nk4: v4\r\n\r\n"
Right [[("k1","v1"),("k2","v2")],[("k3","v3"),("k4","v4")]]
答案 1 :(得分:1)
您的代码不是自包含的,实际问题不明确。但是,我怀疑你的困境实际上是由解析键的方式引起的;特别是,\r\nk
之类的东西是一个有效的密钥,根据你的解析器:
λ> parseOnly parsePair "\r\nk: v\r\n"
Right ("\r\nk","v")
需要修复。
此外,由于一个EOL 分隔(而非终止)键值对,因此不应在parsePair
结束时使用EOL解析器。
另一个切线问题:因为您使用many1
组合器而非ByteString
面向解析器(例如takeTill
),您的值的类型为String
而不是{{1 }}。这可能不你想要什么,这里,因为它首先违背了使用ByteString
的目的。见Performance considerations。
我建议进行以下重构:
ByteString
我已经重命名了你的解析器,为了与{-# LANGUAGE OverloadedStrings #-}
import Data.ByteString ( ByteString )
import Data.Attoparsec.ByteString.Char8 ( Parser
, count
, endOfLine
, parseOnly
, sepBy
, string
, takeTill
)
-- convenient type synonyms
type KVPair = (ByteString, ByteString)
type Msg = [KVPair]
pair :: Parser KVPair
pair = do
k <- key
_ <- string ": "
v <- value
return (k, v)
where
key = takeTill (\c -> c == ':' || isEOL c)
value = takeTill isEOL
isEOL c = c == '\n' || c == '\r'
-- one EOL separates key-value pairs
msg :: Parser Msg
msg = sepBy pair endOfLine
-- two EOLs separate messages
msgs :: Parser [Msg]
msgs = sepBy msg (count 2 endOfLine)
的一致,没有一个“解析”作为前缀:
attoparsec
- &gt; parsePair
pair
- &gt; parseListPairs
msg
- &gt; parseMsg
msgs
好;在这种情况下,你确实想要失败。
λ> parseOnly keyValuePair "\r\nk: v"
Left "string"