如果您尝试将此字符串解码为 utf-8,如您所知,您将收到“UnicodeDecode”错误,因为这些虚假的 cp1252 字符是无效的 utf-8 -
但是,Python 编解码器允许您注册处理编码/解码的回调 http://docs.python.org/library/codecs.html#codecs.register_errorg 错误,使用 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并且out范围 (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")
#new_char = u"_"
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çã