2015-11-02 70 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输出)。 –