如果您尝试将此字符串解码为utf-8,就像您已经知道的那样,您将收到一个"UnicodeDecode"错误,因为这些虚假的cp1252字符是无效的utf-8 -
但是,Python编解码器允许您注册一个回调函数来处理编码/解码错误,使用codecs.register_error函数 - 它以UnicodeDecodeerror作为参数 - 您可以编写这样的处理程序,尝试将数据解码为"cp1252",并继续对其余字符串进行utf-8解码。
在我的utf-8终端中,我可以构建一个混合不正确的字符串,如下所示:
>>> a = u"maçã ".encode("utf-8") + u"maçã ".encode("cp1252")
>>> print a
maçã ma��
>>> a.decode("utf-8")
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 9-11: invalid data
我在这里编写了所述的回调函数,并发现一个问题:即使您将要解码的字符串的位置增加1,以便它从下一个字符开始,如果下一个字符也不是utf-8且超出范围(128),则错误会在第一个超出范围(128)的字符处引发 - 这意味着,如果找到连续的非ascii、非utf-8字符,则解码会“回退”。解决这个问题的方法是在error_handler中添加一个状态变量,以检测这种“回退”,并从上次调用它时恢复解码 - 在这个简短的示例中,我将其实现为全局变量 - (每次调用解码器之前必须手动将其重置为“-1”):
import codecs
last_position = -1
def mixed_decoder(unicode_error):
global last_position
string = unicode_error[1]
position = unicode_error.start
if position <= last_position:
position = last_position + 1
last_position = position
new_char = string[position].decode("cp1252")
return new_char, position + 1
codecs.register_error("mixed", mixed_decoder)
并在控制台上:
>>> a = u"maçã ".encode("utf-8") + u"maçã ".encode("cp1252")
>>> last_position = -1
>>> print a.decode("utf-8", "mixed")
maçã maçã
str.translate()
比一堆替换更适合你尝试的操作。例如:cp1252_to_unicode = string.maketrans({...})
然后l.translate(cp1252_to_unicode)
。 - Gareth Latty