19

ほとんどが 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)

これに対処する方法についてのアイデアはありますか?

4

5 に答える 5

29

この文字列を utf-8 としてデコードしようとすると、ご存知のように、これらの偽の cp1252 文字は無効な utf-8 であるため、「UnicodeDecode」エラーが発生します -

ただし、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ではない場合、次のchratcerで開始されるようになります。範囲外 (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çã 
于 2012-04-04T11:16:44.210 に答える
1

今日これに入ったばかりなので、ここに私の問題と私自身の解決策があります:

original_string = 'Notifica\xe7\xe3o de Emiss\xe3o de Nota Fiscal Eletr\xf4nica.'

def mixed_decoding(s):
    output = ''
    ii = 0
    for c in s:
        if ii <= len(s)-1:
            if s[ii] == '\\' and s[ii+1] == 'x':
                b = s[ii:ii+4].encode('ascii').decode('unicode-escape')
                output = output+b
                ii += 3
            else:
                output = output+s[ii]
        ii += 1
    print(output)
    return output

decoded_string = mixed_decoding(original_string)

これで次のように表示されます:
>>> Notificação de Emissão de Nota Fiscal Eletrônica.

于 2021-05-18T14:28:23.217 に答える