我有一个文件,其中大部分是UTF-8,但某些Windows 1252字符也发现自己到底。
我创建了一个表,从Windows 1252(CP1252)字符它们的Unicode同行地图,并想用它来修复错误编码的字符,如
cp1252_to_unicode = {
"\x85": u'\u2026', # …
"\x91": u'\u2018', # ‘
"\x92": u'\u2019', # ’
"\x93": u'\u201c', # “
"\x94": u'\u201d', # ”
"\x97": u'\u2014' # —
}
for l in open('file.txt'):
for c, u in cp1252_to_unicode.items():
l = l.replace(c, u)
但是,试图做替换在UnicodeDecodeError错误这样的结果被提出,例如:
"\x85".replace("\x85", u'\u2026')
UnicodeDecodeError: 'ascii' codec can't decode byte 0x85 in position 0: ordinal not in range(128)
任何想法如何面对呢?
如果您尝试此字符串解码为UTF-8,因为你已经知道了,你会得到一个“UnicodeDecode”的错误,因为这些虚假CP1252字符无效UTF-8 -
然而,Python的编解码器,允许你注册一个回调来处理编码/ decodin摹错误,与codecs.register_error功能-它得到的UnicodeDecodeError AA参数-你可以写这样atempts的数据为“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到字符串解码的位置,所以,这将在未来chratcer开始,如果接下来的文字也不是UTF-8和出的范围(128),误差在第一凸起超出范围(128)字符 - 这意味着,解码“走回到”如果连续非ASCII,非UTF-8字符被发现。
该worka圆这是在检测这个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çã
与感谢jsbueno和其他谷歌搜索敲击等冲击我解决了这种方式。
#The following works very well but it does not allow for any attempts to FIX the data.
xmlText = unicode(xmlText, errors='replace').replace(u"\uFFFD", "?")
该版本允许修复无效字符一个有限的机会。 未知字符被替换成一个安全值。
import codecs
replacement = {
'85' : '...', # u'\u2026' ... character.
'96' : '-', # u'\u2013' en-dash
'97' : '-', # u'\u2014' em-dash
'91' : "'", # u'\u2018' left single quote
'92' : "'", # u'\u2019' right single quote
'93' : '"', # u'\u201C' left double quote
'94' : '"', # u'\u201D' right double quote
'95' : "*" # u'\u2022' bullet
}
#This is is more complex but allows for the data to be fixed.
def mixed_decoder(unicodeError):
errStr = unicodeError[1]
errLen = unicodeError.end - unicodeError.start
nextPosition = unicodeError.start + errLen
errHex = errStr[unicodeError.start:unicodeError.end].encode('hex')
if errHex in replacement:
return u'%s' % replacement[errHex], nextPosition
return u'%s' % errHex, nextPosition # Comment this line out to get a question mark
return u'?', nextPosition
codecs.register_error("mixed", mixed_decoder)
xmlText = xmlText.decode("utf-8", "mixed")
基本上,我试图把它变成UTF8。 对于失败,我只是把它转换为十六进制,所以我可以显示或在自己的表看它的任何字符。
这是不漂亮,但它确实让我做搞砸数据的意义