【问题标题】:'ascii' codec can't encode error when reading using Python to read JSON'ascii' 编解码器在使用 Python 读取 JSON 时无法编码错误
【发布时间】:2015-02-08 20:01:50
【问题描述】:

还有一个人无法找到正确的魔法咒语来让 Python 打印 UTF-8 字符。

我有一个 JSON 文件。 JSON 文件包含字符串值。这些字符串值之一包含字符“à”。我有一个 Python 程序,它读取 JSON 文件并打印其中的一些字符串。有时当程序尝试打印包含“à”的字符串时,我会收到错误

UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 12: ordinal not in range(128)

这很难重现。有时,稍微不同的程序能够打印字符串“à”。仅包含此字符串的较小 JSON 文件不会出现此问题。如果我开始在代码周围添加encode('utf-8')decode('utf-8'),它会以不可预知的方式改变发生的事情。我无法创建出现此问题的最小代码片段和输入。

我像这样加载 JSON 文件。

with codecs.open(filename, 'r', 'utf-8') as f:
    j = json.load(f)

我会像这样拔掉有问题的字符串。

s = j['key']

后来我做了一个print,其中包含s,然后查看错误。

我很确定原始文件是 UTF-8 格式,因为在交互式命令行中

codecs.open(filename, 'r', 'utf-8').read()

返回一个字符串但是

codecs.open(filename, 'r', 'ascii').read()

给出关于 ascii 编解码器无法解码某某字节的错误。以字节为单位的文件大小与wc -c 返回的字符数相同,而且我没有看到任何其他看起来像非 ASCII 字符的东西,所以我怀疑问题完全出在这个高 ASCII 字符“à ”。

我没有在我的代码中对str() 进行任何显式调用。

我已经多次通过Python Unicode HOWTO。我知道我应该“三明治”处理 unicode。我想我正在这样做,但显然我仍然误解了一些东西。

我很困惑,因为似乎如果我在 codecs.open 调用中指定“utf-8”,那么一切都应该在 UTF-8 中发生。我不明白 ASCII 编解码器是如何潜入的。

我做错了什么?我该如何调试呢?


编辑:使用io 模块代替codecs。结果一样。


编辑:我没有最小的例子,但至少我有一个最小的重现场景。

我正在打印一个从导致问题的 JSON 中的字符串派生的对象。所以下面给出了一个错误。

print(myobj)

(请注意,我使用的是from __future__ import print_function,尽管这似乎没有什么区别。)

在我的对象的__str__ 函数返回值的末尾放置一个encode('utf-8') 并不能修复错误。但是将打印行更改为此。

print("%s" % myobj)

这在我看来是错误的。我希望这两个打印调用是等效的。


我可以通过 sys.setdefaultencoding hack 来完成这项工作:

import sys
reload(sys)
sys.setdefaultencoding("UTF-8")

但这显然是个坏主意,可能会导致 Python 以其他方式出现故障。

这样做的正确方法是什么?我试过了

env PYTHONIOENCODING=UTF-8 ./myscript.py

但这没有用。 (不出所料,因为问题是默认编码,而不是 io 编码。)

【问题讨论】:

  • 什么是print(repr(myobj))
  • print(repr(myobj)) 不会抛出错误。它按预期打印 repr 字符串。 (例如,转义“\n”而不是换行符。)
  • 我问过它是什么(导致问题的对象),而不是repr(myobj) 是否会导致错误(它不应该)。您是否使用自定义对象(自定义__unicode____str__)来解析 json?为什么?

标签: python json unicode encoding utf-8


【解决方案1】:

当您直接写入文件或将标准输出重定向到文件或管道时,默认编码是 ASCII,您必须在写入 Unicode 字符串之前对其进行编码。使用打开的文件句柄,您可以设置编码以自动执行此操作,但使用 print 您必须使用 encode() 方法。

print s.encode('utf-8')

建议使用较新的io 模块代替codecs,因为它具有改进的实现并且与Py3.x open() 向前兼容。

【讨论】:

  • 您应该在打印 Unicode 之前对其进行编码。不要在脚本中对环境的字符编码进行硬编码。改为设置正确的区域设置(LANG、LC_CTYPE、LC_ALL)和/或PYTHONIOENCODING envvar。
猜你喜欢
  • 2015-01-28
  • 2015-02-03
  • 2019-09-01
  • 2017-03-31
  • 1970-01-01
  • 2017-03-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-29
相关资源
最近更新 更多