Python的 - 处理编码的混合文件(Python - dealing with mixed-en

2019-06-23 09:43发布

我有一个文件,其中大部分是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)

任何想法如何面对呢?

Answer 1:

如果您尝试此字符串解码为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çã 


Answer 2:

与感谢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。 对于失败,我只是把它转换为十六进制,所以我可以显示或在自己的表看它的任何字符。

这是不漂亮,但它确实让我做搞砸数据的意义



文章来源: Python - dealing with mixed-encoding files