我正在尝试创建一个解析器(使用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的转换为我节省了大量时间和“源空间”:)
答案 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”,与截断的内容不匹配。尝试用ByteString
和parsec
解析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',具体取决于输入的编码方式。