如何在Python中将HTML非ASCII数据编码为UTF-8
我试着这么做,但遇到了这些错误:
>>> import re
>>> x = 'Ingl\xeas'
>>> x
'Ingl\xeas'
>>> print x
Ingl�s
>>> x.decode('utf8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.6/encodings/utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 4-5: unexpected end of data
>>> x.decode('utf8', 'ignore')
u'Ingl'
>>> x.decode('utf8', 'replace')
u'Ingl\ufffd'
>>> print x.decode('utf8', 'replace')
Ingl�
>>> print x.decode('utf8', 'xmlcharrefreplace')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.6/encodings/utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
TypeError: don't know how to handle UnicodeDecodeError in error callback
当我使用打印语句时,我希望得到这个:
>>> print x
u'Inglês'
任何帮助都很欢迎。
3 个回答
一些观察结果:
(1) latin1
可以解码任何8位字节,而不会抛出错误。只有在你尝试了所有其他方法后,才应该使用 latin1
。可以使用chardet来帮助判断某个文件、网页或XML流的编码方式。
(2) 基于非常有限的证据(一个字符),可能的替代方案:
>>> import unicodedata as ucd
>>> for codepage in range(1250, 1259):
... try:
... uc = "\xea".decode(str(codepage))
... except UnicodeDecodeError:
... pass
... if uc == u'\xea': print codepage, ucd.name(uc)
...
1252 LATIN SMALL LETTER E WITH CIRCUMFLEX
1254 LATIN SMALL LETTER E WITH CIRCUMFLEX
1256 LATIN SMALL LETTER E WITH CIRCUMFLEX
1258 LATIN SMALL LETTER E WITH CIRCUMFLEX
>>>
(3) 范围 U+0080 到 U+009F(包括这两个值)被分配给“C1控制字符”,而且除了unicode.org,没人知道这些字符有什么用。无论你使用什么编码(即使是UTF-8),在解码成unicode后,你还不能完全放心。要检查这个范围内是否有字符。如果发现有,说明你的数据可能损坏,或者你选择的编码不正确。
def check_for_c1_control_characters(unicode_obj):
return any('\u0080' <= c <= '\u009F' for c in unicode_obj)
或者可以使用正则表达式,就像这个例子展示的那样,来修复数据损坏的多种方式之一。
Ingl\xeas
这个内容不是UTF-8编码的,可能是用Windows-1252或latin1编码的。所以你首先需要把它解码。只有这样,你才能把它转成UTF-8编码。
因此:
>>> x = 'Ingl\xeas'
>>> print x.decode("cp1252")
Inglês
类似地,
>>> x.decode("cp1252").encode("UTF-8")
'Ingl\xc3\xaas'
这是正确的UTF-8表示方式。
顺便说一下,在Python 3中,你可以(至少在Windows的交互式控制台中)直接输入
>>> x = 'Ingl\xeas'
>>> print (x)
Inglês
因为Python 3中的字符串总是Unicode字符串(不包括bytes
对象)。
在解码数据之前,你需要知道输入数据是怎么编码的。在你的一些尝试中,你试图用UTF-8来解码,但Python报错了,因为输入的数据并不是有效的UTF-8格式。看起来它可能是latin-1编码。这个方法对我有效:
>>> x = 'Ingl\xeas'
>>> print x.decode('latin1')
Inglês
你提到“非ASCII的HTML”。如果你在写一个网络服务器脚本,并且从HTTP请求中获取数据,你应该检查一下Content-Type这个头信息。在理想情况下,它会告诉你客户端使用了什么编码来传输数据。不过要记住,客户端可能会出现问题。
希望这能帮到你!