Python:解码由unicode代码点和unicode文本组成的字符串

时间:2015-11-02 19:22:48

标签: python unicode

解析一些HTML内容我得到以下字符串:

"regex": /(^[0-9a-zA-Z]+(?:[._-][0-9a-zA-Z]+)*)_@([0-9a-zA-Z]+(?:[._-][0-9a-zA-Z]+)*\.[0-9a-zA-Z]{2,3})$/i,

处理它的常见建议似乎是使用unicode_escape进行解码。但是,这导致以下结果:

АБВ\u003d\"res

转义字符被正确解码,但由于某种原因,西里尔字母会被破坏。除了使用正则表达式来提取看起来像unicode字符串的所有内容之外,只使用unicode_escape对它们进行解码,然后将所有内容放入一个新字符串中,还有哪些其他方法可以用Python中的unicode代码点解码字符串?

2 个答案:

答案 0 :(得分:4)

unicode_escape将输入视为 Latin-1 encoded ;任何不表示Python字符串文字转义序列的字节都会被解码,将字节直接映射到Unicode代码点。你给它UTF-8字节,所以西里尔字符用2个字节表示,每个字节解码为两个拉丁-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,可以通过重新编码为Latin-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 + 0000-U + 00FF),则失败

上述Python 3等效使用codecs.encode()

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

答案 1 :(得分: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