如您所知,如果您尝试将此字符串解码为utf-8,则会收到“ UnicodeDecode”错误,因为这些伪造的cp1252字符是无效的utf-8-
但是,Python编解码器允许您使用codecs.register_error函数注册用于处理编码/解码错误的回调-它获取UnicodeDecodeerror aa参数-您可以编写这样的处理程序,以免将数据解码为“ 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并从下一个字符开始,它将在下一个字符开始如果是range(128)的字符,则会在超出range(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çã