如何在Python中将HTML非ASCII数据编码为UTF-8

2 投票
3 回答
10578 浏览
提问于 2025-04-15 20:07

我试着这么做,但遇到了这些错误:

>>> 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 个回答

0

一些观察结果:

(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)

或者可以使用正则表达式,就像这个例子展示的那样,来修复数据损坏的多种方式之一。

0
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对象)。

7

在解码数据之前,你需要知道输入数据是怎么编码的。在你的一些尝试中,你试图用UTF-8来解码,但Python报错了,因为输入的数据并不是有效的UTF-8格式。看起来它可能是latin-1编码。这个方法对我有效:

>>> x = 'Ingl\xeas'
>>> print x.decode('latin1')
Inglês

你提到“非ASCII的HTML”。如果你在写一个网络服务器脚本,并且从HTTP请求中获取数据,你应该检查一下Content-Type这个头信息。在理想情况下,它会告诉你客户端使用了什么编码来传输数据。不过要记住,客户端可能会出现问题。

希望这能帮到你!

撰写回答