1

我正在尝试创建一个解析器(使用 parsec),它解析由换行符、逗号、分号和 unicode 破折号(ndash 和 mdash)分隔的标记:

authorParser = do
    name <- many1 (noneOf [',', ':', '\r', '\n', '\8212', '\8213'])
    many (char ',' <|> char ':' <|> char '-' <|> char '\8212' <|> char '\8213')

但是 ndash-mdash (\8212, \8213) 部分永远不会“成功”,我得到的解析结果无效。

如何使用 char 解析器指定 unicode 破折号?

PS我也试过(chr 8212),(chr 8213)。它没有帮助。

补充:最好使用 Data.Text。从 ByteStrings 疯狂切换到 Data.Text 为我节省了大量时间和“源空间”:)

4

1 回答 1

3

为我工作:

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(严格或懒惰,没关系),则Chars 在打包时会被截断,只保留最低有效 8 位,因此 '\8212' 变为 20,而 '\8213' 变为 21。如果输入流的构造方式相同,这仍然是一种工作方式,只有Char与 20 或 21 模 256 一致的所有 s 将被映射到与其中一个破折号相同的位置。

但是,输入流很可能是 UTF-8 编码的,然后破折号分别编码为三个字节,分别为“\226\128\148”。“\226\128\149”,这与截断得到的不匹配。尝试使用ByteStringand来解析 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' 匹配,具体取决于输入的编码方式。

于 2011-12-19T18:22:50.670 回答