Parsec匹配单个unicode字符

时间:2011-12-19 17:16:12

标签: haskell unicode parsec

我正在尝试创建一个解析器(使用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破折号?

P.S。我也尝试过(chr 8212),(chr 8213)。它没有帮助。

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

1 个答案:

答案 0 :(得分: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,"

你是怎么试的?

以上是使用普通String,它可以正常工作,因为Char是一个完整的解码代码点。它与其他类型的输入流不太一样。 Text可能也适用于此示例,我认为破折号在那里被编码为单个代码单元。然而,对于ByteString,情况更复杂。如果你使用普通Data.ByteString.Char8(严格或懒惰,无关紧要),Char s在打包时被截断,只保留最低8位,所以'\ 8212'变为20并且'\ 8213'变为21.如果输入流以相同的方式构造,那仍然有效,只有所有Char一致到20或21模256将被映射到相同的一个破折号。

但是,输入流很可能是UTF-8编码,然后破折号分别编码为三个字节,“\ 226 \ 128 \ 148”。 “\ 226 \ 128 \ 149”,与截断的内容不匹配。尝试用ByteStringparsec解析utf-8编码的文本有点复杂,组成解析结果的单位不是单个字节,而是字节序列,长度为1-4每个

要使用noneOf,您需要

instance Text.Parsec.Prim.Stream ByteString m Char

哪个做对了。 Text.Parsec.ByteString[.Lazy]中提供的实例没有,它使用Data.ByteString[.Lazy].Char8界面,因此en-dash将成为单个'\ 20'不匹配'\ 8212'或生成三个Chars ,'\'对于uncons的三次连续调用,'\ 226','\ 128'和'\ 148',其中任何一个都不匹配'\ 8212',具体取决于输入的编码方式。