【问题标题】:UnicodeDecodeError in json.dumpjson.dump 中的 UnicodeDecodeError
【发布时间】:2014-03-08 18:15:53
【问题描述】:

我有一个复杂的 JSON 可序列化数据结构,其中包含 unicode 字符串和 utf-8 字节字符串。

当我尝试使用ensure_ascii=False 序列化结构时,它失败了:

Python 2.7.5+ (default, Sep 19 2013, 13:48:49) 
[GCC 4.8.1] on linux2
>>> import json
>>> json.dumps(['\xd0\xb2', u'\xd0\xb2'], ensure_ascii=False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/json/__init__.py", line 250, in dumps
    sort_keys=sort_keys, **kw).encode(obj)
  File "/usr/lib/python2.7/json/encoder.py", line 210, in encode
    return ''.join(chunks)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd0 in position 1: ordinal not in range(128)
>>> 

我明白为什么this happens,但有没有更简单或内置的方法可以让它工作,而不是递归地遍历数据结构、查找字节字符串并将它们解码为 un​​icode?​​p>

【问题讨论】:

  • 为什么首先将字节串添加到结构中?
  • 我无法控制它。这是一本由 API 用户更新的字典。我想让它万无一失。
  • 这个建议很有帮助:nedbatchelder.com/text/unipain.html
  • 是的,我知道这一切。在理想世界中,这已经足够了。有时你只需要让它发挥作用。

标签: python json unicode python-unicode


【解决方案1】:

AFAIK 序列化为 JSON 格式的原因是为了存储或传输一些信息。如果您指定ensure_ascii = False,则不会对非ascii 字符进行编码,这完全没有意义,因为您要对数据进行编码和序列化。

基本上,您正在尝试获取包含非编码字符的字符串,这是不可能的。

来自官方文档:

如果 ensure_ascii 为 True(默认值),则输出中的所有非 ASCII 字符都使用 \uXXXX 序列进行转义,结果是仅由 ASCII 字符组成的 str 实例。如果 ensure_ascii 为 False,则写入 fp 的某些块可能是 unicode 实例。这通常是因为输入包含 unicode 字符串或使用了编码参数。除非 fp.write() 明确理解 unicode(如在 codecs.getwriter() 中),否则这可能会导致错误。

另一方面,您正在设计 API 并不能说明您无法控制输入。 API 在某种程度上是一种契约:如果给出了一些输入,就会返回一些输出。因此,您可以并且应该始终指定您的期望。

在您的情况下,您可以一一检查元素,并将字节串转换为 unicode。话虽如此,我的建议是你强迫你的用户使用 unicode 并且 不要指定 ensure_ascii = False

对我来说,理解编码和避免问题的一般规则如下:

  1. 代码中的字符串必须是 unicode。
  2. 导入数据时,将其解码为 un​​icode。导出时,编码。这需要双方同意他们使用的编码,否则你只会得到噪音。

【讨论】:

  • 我有意使用ensure_ascii = False,因为我将序列化数据保存到数据库中,这使我可以节省 66% 的数据库内存,并在我直接访问数据库时使其更具可读性:@ 987654324@ -> 202, len(json.dumps(u'ф' * 100).encode('utf-8')) -> 602
  • > 如果您指定 ensure_ascii = False,则不编码非 ascii 字符,这根本没有意义,因为您正在寻找编码和序列化数据。
  • 如果你不确保_ascii,你可以有unicode输出。如果您像示例中那样再次重新编码,它可以工作但看起来很麻烦,因为您有一个 unicode json 字符串,然后您将其编码为字节。那我不知道...似乎 json.dumps 与混合的 unicode 和字节混淆了,因此您可以要求用户使用所有 unicode,或者检查您的输入并将其全部转换为字节或 unicode。
猜你喜欢
  • 2016-06-23
  • 2014-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多