问题
您的代码不是独立的,实际问题尚不清楚。但是,我怀疑您的问题实际上是由解析键的方式引起的;\r\nk
特别是,根据您的解析器,类似的东西是一个有效的密钥:
λ> parseOnly parsePair "\r\nk: v\r\n"
Right ("\r\nk","v")
这需要修复。
此外,由于一个 EOL分离(而不是终止)键值对,因此不应在parsePair
解析器结束时使用 EOL。
另一个切线问题:因为您使用many1
组合器而不是面向ByteString
的解析器(例如takeTill
),所以您的值具有 typeString
而不是ByteString
. 在这里,这可能不是您想要的,因为它首先破坏了使用的目的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)
为了与 's 保持一致,我已重命名您的解析器,attoparsec
其中没有一个以“parse”作为前缀:
parsePair
-->pair
parseListPairs
-->msg
parseMsg
-->msgs
GHCi 中的测试
λ> parseOnly keyValuePair "\r\nk: v"
Left "string"
好的; 在这种情况下,您确实想要失败。
λ> parseOnly keyValuePair "k: v"
Right ("k","v")
λ> parseOnly msg "k: v\r\nk2: v2\r\n"
Right [("k","v"),("k2","v2")]
λ> parseOnly msgs "k1: v1\r\nk2: v2\r\n\r\nk3: v3\r\nk4: v4"
Right [[("k1","v1"),("k2","v2")],[("k3","v3"),("k4","v4")]]
λ> parseOnly msgs "k: v"
Right [[("k","v")]]