2015-11-02 108 views
1

一些解析HTML內容,我得到了下面的字符串:的Python:解碼同時包含Unicode代碼點的字符串和Unicode文本

АБВ\u003d\"res 

上處理的通常建議它似乎是使用unicode_escape解碼。但是,結果如下:

ÐÐÐ="res 

轉義字符得到正確解碼,但西裏爾字母由於某種原因被弄壞。除了使用正則表達式來提取看起來像unicode字符串的所有內容,只需使用unicode_escape解碼它們,然後將所有內容都放入一個新字符串中,那麼還有哪些其他方法可以用Python中的unicode代碼點解碼字符串?

+1

請向我們展示一個顯示此行爲的[mcve],其中包括您解碼的原始值的'repr()'輸出。 –

+1

推測這是Python 2.7並且輸入是一個*字節的字符串*?所以repr可以是''\ xd0 \ x90 \ xd0 \ x91 \ xd0 \ x92 \\ u003d \\'res''。 –

+0

@MartijnPieters這個_is_是一個極小的例子。repr()輸出是 'Ð\ x90 \ x91 \ x92 =「res」 不,這是Python 3. – Dariush

回答

2

unicode_escape將輸入視爲Latin-1編碼;任何不代表Python字符串文字轉義序列的字節都將解碼的映射字節直接解碼爲Unicode碼點。你把它UTF-8字節,所以西里爾字符表示與各2個字節,其中解碼的兩個Latin-1的每一個字符,其中一個是U + 00D0 Ð,其他不可打印:

>>> print repr('АБВ\\u003d\\"res') 
'\xd0\x90\xd0\x91\xd0\x92\\u003d\\"res' 
>>> print repr('АБВ\\u003d\\"res'.decode('latin1')) 
u'\xd0\x90\xd0\x91\xd0\x92\\u003d\\"res' 
>>> print 'АБВ\\u003d\\"res'.decode('latin1') 
ÐÐÐ\u003d\"res 

這種的誤解碼被稱爲Mojibake,並且可以通過重新編碼被修復以拉丁語-1,然後從正確的編解碼器(UTF-8你的情況)進行解碼:

>>> print 'АБВ\u003d\\"res'.decode('unicode_escape') 
ÐÐÐ="res 
>>> print 'АБВ\u003d\\"res'.decode('unicode_escape').encode('latin1').decode('utf8') 
АБВ="res 

注意,這將失敗如果\uhhhh轉義序列對Latin-1範圍之外的代碼點進行編碼(U + 0 000-U + 00FF)。

Python的3當量的上述用途codecs.encode()

>>> import codecs 
>>> codecs.decode('АБВ\\u003d\\"res', 'unicode_escape').encode('latin1').decode('utf8') 
'АБВ="res' 
0

正則表達式真的是最簡單的解決方案(Python 3中):

text = 'АБВ\\u003d\\"re' 
re.sub(r'(?i)(?<!\\)(?:\\\\)*\\u([0-9a-f]{4})', lambda m: chr(int(m.group(1), 16)), text) 

此正常工作與任何4半字節Unicode轉義,並可以很容易地擴展到其他逃生。

對於Python 2,使所有字符串u''字符串,並使用unichr

+0

在Python 2上,這隻適用於U + 0000-U + 00FF。 –

+0

好的,注意到這是針對Python 3的。(使用unicode字符串和'unichr'使其適用於Python 2) – nneonneo

+0

然而,OP幾乎肯定使用Python 2;他們有一個UTF-8字節串(這就是爲什麼他們得到他們在他們的問題中發佈的Mojibake輸出)。 –