您在这里有Mojibake 数据;使用错误的编解码器从字节解码的 UTF-8 数据。
诀窍是在生成 JSON 输出之前找出用于解码的编码。如果您假设编码是 Windows 代码页 1252,则可以修复前两个示例:
>>> 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
但是这个编解码器在第三次失败:
>>> 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 左双引号代码点的 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 库非常有帮助地提醒我使用“草率”的 CP1252 编解码器来解决该问题,将不存在的字节一对一映射(UTF-8 字节到 Latin-1 Unicode 点)。然后,库将生成的“花式引号”映射到 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 交给您的混乱中。但是,如果您有一半的机会,请不要犹豫地斥责向您提供这些数据的人。他们制作了一个可爱的垃圾。