为我工作:
Prelude Text.ParserCombinators.Parsec> let authorName = do { name <- many1 (noneOf ",:\r\n\8212\8213"); many (oneOf ",:-\8212\8213"); }
Prelude Text.ParserCombinators.Parsec> parse authorName "" "my Name,\8212::-:\8213,"
Right ",\8212::-:\8213,"
你是怎么尝试的?
上面使用的是 plain String
,因为 aChar
是一个完整的未编码代码点,所以可以正常工作。它与其他类型的输入流不一样。Text
可能也适用于这个例子,我认为破折号在那里被编码为单个代码单元。然而,对于 来说ByteString
,事情要复杂得多。如果您使用的是普通Data.ByteString.Char8
(严格或懒惰,没关系),则Char
s 在打包时会被截断,只保留最低有效 8 位,因此 '\8212' 变为 20,而 '\8213' 变为 21。如果输入流的构造方式相同,这仍然是一种工作方式,只有Char
与 20 或 21 模 256 一致的所有 s 将被映射到与其中一个破折号相同的位置。
但是,输入流很可能是 UTF-8 编码的,然后破折号分别编码为三个字节,分别为“\226\128\148”。“\226\128\149”,这与截断得到的不匹配。尝试使用ByteString
and来解析 utf-8 编码的文本parsec
有点复杂,组成解析结果的单元不是单个字节,而是字节序列,每个长度为 1-4。
要使用noneOf
,您需要一个
instance Text.Parsec.Prim.Stream ByteString m Char
哪个是正确的。中提供的实例Text.Parsec.ByteString[.Lazy]
没有,它使用Data.ByteString[.Lazy].Char8
接口,所以一个破折号会变成一个 '\20' 不匹配 '\8212' 或产生三个Chars
'\226'、'\128' 和 '\148'在对 的三个连续调用中uncons
,没有一个与 '\8212' 匹配,具体取决于输入的编码方式。