Python json忽略非ascii字符UnicodeDecodeError:'ascii'编解码器无法解码字节

时间:2014-05-27 10:31:49

标签: python json python-2.7 encoding utf-8

Python 2.7.3

我已经阅读了json / dumps UnicodeDecodeError周围的所有相关线程,他们中的大多数都希望我理解我需要的编码。在我的情况下,我正在创建一个json,其中包含来自各种服务(某些p4命令行)的各种键值,可能是不同的编码。我有一张类似这样的地图

map = {"system1": some_data_from_system1, "system2", some_data_from_system2}
json.dumps(map)

抛出“UnicodeDecodeError:'ascii'编解码器无法解码位置737中的字节0x92:序数不在范围内(128)”

我想将ASCII字符偶尔转储到文件中p4 checkin / jira可能有非ascii字符,并且完全可以忽略它。我试过“ensure_ascii = False”并没有解决问题。我真正想要的是编码器在途中简单地忽略任何非ascii字符。我认为这是合理的,但找不到任何出路。

建议?

3 个答案:

答案 0 :(得分:2)

传入时,json.dumps()json.dump()函数会尝试解码字节字符串为Unicode值,默认情况下使用UTF-8:

>>> map = {"system1": '\x92'}
>>> json.dumps(map)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mj/Development/Library/buildout.python/parts/opt/lib/python2.7/json/__init__.py", line 243, in dumps
    return _default_encoder.encode(obj)
  File "/Users/mj/Development/Library/buildout.python/parts/opt/lib/python2.7/json/encoder.py", line 207, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/Users/mj/Development/Library/buildout.python/parts/opt/lib/python2.7/json/encoder.py", line 270, in iterencode
    return _iterencode(o, 0)
UnicodeDecodeError: 'utf8' codec can't decode byte 0x92 in position 0: invalid start byte
>>> map = {"system1": u'\x92'.encode('utf8')}
>>> json.dumps(map)
'{"system1": "\\u0092"}'

您可以将encoding关键字参数设置为对字节字符串(str)字符使用不同的编码。

这些函数执行此操作是因为JSON是对所有字符串使用Unicode的标准。如果您将编码为UTF-8的数据提供给它,则会失败,如上所示。

在Python 2上,输出也是一个字节字符串,编码为UTF-8。 IT可以安全地写入文件。将ensure_ascii参数设置为False会改变这种情况,而您将获得Unicode,这显然是您不想要的。

因此,您需要确保将放入 json.dumps()函数的内容始终采用相同的编码,已解码为{{1}对象。如果您不关心偶尔错过的代码点,您可以通过将错误处理程序设置为unicodereplace来强制执行解码:

ignore

强制解码字符串,用替换字符替换任何未被识别为ASCII码点的字节:

map = {"system1": some_data_from_system1.decode('ascii', errors='ignore')}

此处插入U+FFFD REPLACEMENT CHARACTER代码点代替未知代码点。您也可以使用>>> '\x92'.decode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0x92 in position 0: ordinal not in range(128) >>> '\x92'.decode('ascii', errors='replace') u'\ufffd' 完全忽略此类字节。

答案 1 :(得分:0)

我使用了How to get string objects instead of Unicode ones from JSON in Python?和上面答案的组合来完成这段日志记录。

如上所述,some_data_from_system{1|2}不是字符串。问题是关于一般错误记录系统。当出现问题时,您希望尽可能多地从多个子系统中转储信息以供人工检查。子系统在环境之间变化,并且当它们返回表示出错的“jsons”时,并不总是知道它们使用什么编码。为此,我从其他线程中窃取了以下方法,但本质上基本上是带有“忽略”的decode方法

请注意 :这不是一个非常高效的方法(大多数盲目递归通常都不是)。所以这不适合典型的生产应用;根据数据,可能会遇到无限循环。但是,假设您了解免责声明,则错误记录系统 okay

def convert_encoding(data, encoding = 'ascii'):
    if isinstance(data, dict):
        return dict((convert_encoding(key), convert_encoding(value)) \
             for key, value in data.iteritems())
    elif isinstance(data, list):
        return [convert_encoding(element) for element in data]
    elif isinstance(data, unicode):
        return data.encode(encoding, 'ignore')
    else:
        return data

map = {"system1": some_data_from_system1, "system2", some_data_from_system2}
json.dumps(convert_encoding(map), ensure_ascii = False)

完成后,这种通用方法可用于转储数据。

答案 2 :(得分:0)

如果你的json格式的字符串有非ASCII字符,你需要使用python的dump方法:

myString = "{key: 'Brazilian Portuguese has many differenct characters like  maçã (apple) or Bíblia (Blible)' }" # or a map
myJSON = json.dumps(myString, encoding="latin-1") #use utf8 if appropriate
myJSON = json.loads(myJSON)