2011-12-19 69 views
1

我試圖創建一個解析器(用秒差距),即解析令牌,通過換行,逗號,分號和Unicode破折號(ndash的和mdash)分隔:秒差距匹配單個Unicode字符

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.我試過(8212),(8213)。它沒有幫助。

加成:這是更好地使用Data.Text。從字節串瘋狂到Data.Text交換機爲我節省了大量的時間和「源空間」 :)

+0

我認爲編碼問題應該是一個新問題,沒有足夠的空間來對待評論。 – 2011-12-19 20:51:45

回答

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是一個完整的uncode代碼點。這與其他類型的輸入流不太一樣。 Text可能也適用於這個例子,我認爲破折號被編碼爲一個單一的代碼單元。然而,對於ByteString,事情更加複雜。如果使用普通的Data.ByteString.Char8(嚴格或懶惰,無關緊要),Char會在打包時被截斷,只保留最低有效8位,所以'\ 8212'變成20,'\ 8213'變成21。如果輸入流以相同的方式構建,那仍然有效,但只有所有Char與20或21模256一致纔會被映射爲與其中一個破折號相同。

然而,可能的是,輸入流是UTF-8編碼的,則破折號被編碼爲每三個字節,「\ 226 \ 128 \ 148」 RESP。 「\ 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接口,所以一個連接劃線將成爲一個單一的「\ 20」不匹配「\ 8212」或產生三個Chars,「\ 226」,「\ 128」和' \ 148'連續三次調用uncons,其中沒有一個符合'\ 8212',這取決於輸入的編碼方式。

+0

嗯。如果我從(noneOf [...])切換到(noneOf「...」),它甚至會在更早的階段失敗。也許這是以某種方式與ByteString.Lazy,我正在使用? – zw0rk 2011-12-19 18:45:52

+0

啊。 'ByteString',這是一個線索。添加到我的答案。 – 2011-12-19 18:49:43

+0

謝謝,我已經設法讓noneOf/oneOf'正確'工作,至少與平常人物一樣。但是 - 我是否需要爲var-length字符編寫自己的uncons? – zw0rk 2011-12-19 19:47:20