10

私が管理していないソースから不適切にエンコードされた可能性のある json ドキュメントがあり、次の文字列が含まれています。

d\u00c3\u00a9cor

business\u00e2\u20ac\u2122 active accounts 

the \u00e2\u20ac\u0153Made in the USA\u00e2\u20ac\u009d label

これから、私は彼らが utf-8 hex になる予定の\u00c3\u00a9beceomを集めています。それはある程度理にかなっています。他のものについては、ある種の方向引用符を扱っていると思います。éC3 A9

ここでの私の理論は、これはこれまでに遭遇したことのないエンコーディングを使用しているか、何らかの方法で二重にエンコードされているということです。彼らの壊れた入力を私が理解できるものに変換するためのコードを書いても問題ありません。私が彼らの注意を引いたとしても、彼らがシステムを修正できる可能性は非常に低いからです。

私が理解できるものに彼らの入力を強制する方法はありますか? 記録のために、私はPythonで作業しています。

4

2 に答える 2

16

ftfyモジュールを試す必要があります。

>>> print ftfy.ftfy(u"d\u00c3\u00a9cor")
décor
>>> print ftfy.ftfy(u"business\u00e2\u20ac\u2122 active accounts")
business' active accounts
>>> print ftfy.ftfy(u"the \u00e2\u20ac\u0153Made in the USA\u00e2\u20ac\u009d label")
the "Made in the USA" label
>>> print ftfy.ftfy(u"the \u00e2\u20ac\u0153Made in the USA\u00e2\u20ac\u009d label", uncurl_quotes=False)
the “Made in the USA” label
于 2014-10-28T17:18:25.803 に答える
10

ここにMojibake データがあります。間違ったコーデックでバイトからデコードされた UTF-8 データ。

秘訣は、JSON 出力を生成する前に、デコードに使用されエンコーディングを把握することです。エンコーディングが Windows Codepage 1252 であると仮定すると、最初の 2 つのサンプルを修復できます。

>>> sample = u'''\
... d\u00c3\u00a9cor
... business\u00e2\u20ac\u2122 active accounts 
... the \u00e2\u20ac\u0153Made in the USA\u00e2\u20ac\u009d label
... '''.splitlines()
>>> print sample[0].encode('cp1252').decode('utf8')
décor
>>> print sample[1].encode('cp1252').decode('utf8')
business’ active accounts 

しかし、このコーデックは 3 番目に失敗します。

>>> print sample[2].encode('cp1252').decode('utf8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mpieters/Development/venvs/stackoverflow-2.7/lib/python2.7/encodings/cp1252.py", line 12, in encode
    return codecs.charmap_encode(input,errors,encoding_table)
UnicodeEncodeError: 'charmap' codec can't encode character u'\x9d' in position 24: character maps to <undefined>

最初の 3 つの「奇妙な」バイトは、確かにU+201C LEFT DOUBLE QUOTATION MARKコードポイントの CP1252 Mojibake です。

>>> sample[2]
u'the \xe2\u20ac\u0153Made in the USA\xe2\u20ac\x9d label'
>>> sample[2][:22].encode('cp1252').decode('utf8')
u'the \u201cMade in the USA'

したがって、他の組み合わせはおそらくU+201D RIGHT DOUBLE QUOTATION MARKを意味しますが、後者の文字は通常 CP1252 に存在しない UTF-8 バイトになります。

>>> u'\u201d'.encode('utf8').decode('cp1252')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mpieters/Development/venvs/stackoverflow-2.7/lib/python2.7/encodings/cp1252.py", line 15, in decode
    return codecs.charmap_decode(input,errors,decoding_table)
UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d in position 2: character maps to <undefined>

これは、CP1252 コーデックに 16 進数の 9D 位置がないためですが、コードポイントJSON 出力に含まれているためです。

>>> sample[2][22:]
u'\xe2\u20ac\x9d label'

ftfyライブラリのNed Batchelder は、存在しないバイトを 1 対 1 (UTF-8 バイトから Latin-1 Unicode ポイント) にマッピングして、「ずさんな」CP1252 コーデックを使用してその問題を回避するように警告してくれました。結果の「派手な引用符」は、ライブラリによって ASCII 引用符にマップされますが、これをオフに切り替えることができます。

>>> import ftfy
>>> ftfy.fix_text(sample[2])
u'the "Made in the USA" label'
>>> ftfy.fix_text(sample[2], uncurl_quotes=False)
u'the \u201cMade in the USA\u201d label'

このライブラリはこのタスクを自動化し、標準の Python コーデックがここで実行できるよりも優れた仕事をするので、インストールして、この API があなたに与える混乱に適用するだけです。ただし、可能性が半分しかない場合は、このデータを提供する人々を非難することを躊躇しないでください。彼らは 1 つの素敵なマックアップを作成しました。

于 2014-10-28T17:20:13.100 に答える