在哪个世界会成为é?

时间:2014-10-28 17:08:13

标签: python encoding utf-8 mojibake

我有一个来自我无法控制的来源的不正确编码的json文档,其中包含以下字符串:

d\u00c3\u00a9cor

business\u00e2\u20ac\u2122 active accounts 

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

据此,我正在收集他们打算\u00c3\u00a9 beceom é,这将是utf-8十六进制C3 A9。这有点道理。对于其他人,我假设我们正在处理某些类型的方向引号。

我的理论是,这要么是使用我以前从未遇到的编码,要么是以某种方式进行了双重编码。我很好地编写了一些代码来将他们破碎的输入转换成我能理解的东西,因为如果我把它引起他们的注意,他们很可能无法修复系统。

任何想法如何强迫他们输入我能理解的东西?为了记录,我正在使用Python。

2 个答案:

答案 0 :(得分:13)

您应该尝试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

答案 1 :(得分:8)

你这里有Mojibake data; 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 

但是这个编解码器在第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&#39;怪异的&#39;字节肯定是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编解码器中没有十六进制9D位置,但是代码点 使其成为JSON输出:

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

ftfy library Ned Batchelder如此有帮助地提醒我使用&#39;马虎&#39; CP1252编解码器解决该问题,一对一地映射不存在的字节(UTF-8字节到Latin-1 Unicode点)。由此产生的奇特引用&#39;然后由库映射到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给你的混乱中。但是,如果你有一半的机会,请不要谴责那些提供这些数据的人。他们制作了一个可爱的笨蛋。