1

我有一个简单的程序,它加载一个包含有趣字符的 .json 文件。该程序(见下文)在终端中运行良好,但在 IntelliJ 中出现此错误:

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

关键代码是:

with open(jsonFileName) as f:
    jsonData = json.load(f)

如果我将 open 替换为:

with open(jsonFileName, encoding='utf-8') as f:

然后它适用于 IntelliJ 和终端。我对 Python 和 IntelliJ 插件还是新手,我不明白它们为什么不同。我认为sys.path可能会有所不同,但输出让我认为这不是原因。有人可以解释一下吗?谢谢!

版本:

  • 操作系统:Mac OS X 10.7.4(也在 10.6.8 上测试过)
  • Python 3.2.3(v3.2.3:3d0686d90f55,2012 年 4 月 10 日,11:25:50)/Library/Frameworks/Python.framework/Versions/3.2/bin/python3.2
  • IntelliJ:11.1.3 终极版

文件 (2):

1. unicode-error-demo.py

#!/usr/bin/python

import json
from pprint import pprint as pp
import sys

def main():
    if len(sys.argv) is not 2:
        print(sys.argv[0], "takes one arg: a .json file")
        return

    jsonFileName = sys.argv[1]
    print("sys.path:")
    pp(sys.path)
    print("processing", jsonFileName)

#    with open(jsonFileName) as f:           # OK in Terminal, but BUG in IntelliJ: UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 2: ordinal not in range(128)
    with open(jsonFileName, encoding='utf-8') as f:     # OK in both
        jsonData = json.load(f)
        pp(jsonData)


if __name__ == "__main__":
    main()

2. 编码-temp.json

["™"]
4

2 回答 2

4

JSON.load()函数需要 Unicode 数据,而不是原始字节。Python 自动尝试使用默认编解码器(在您的情况下为 ASCII)为您将字节字符串解码为 Unicode 字符串,但失败了。通过使用UTF-8编解码器打开文件,Python 会为您进行显式转换。请参阅open()功能,其中指出:

在文本模式下,如果未指定编码,则使用的编码取决于平台。

将使用的编码确定如下:

这一切都是在 C 中完成的,但它的 python 等价物是:

if encoding is None:
    encoding = os.device_encoding()
if encoding is None:
    encoding = locale.getpreferredencoding(False)
if encoding is None:
    encoding = 'ASCII'

因此,当您在终端中运行程序时,os.deviceencoding()返回'UTF-8',但在 IntelliJ 下运行时没有终端,如果也没有设置语言环境,python 使用'ASCII'.

Python Unicode HOWTO告诉你所有关于 unicode 字符串和字节串的区别,以及编码。关于该主题的另一篇重要文章是 Joel Spolsky 的Absolute Minimum Unicode 知识文章

于 2012-09-13T15:03:54.087 回答
0

Python 2.x 有字符串和 unicode 字符串。基本字符串用 ASCII 编码。ASCII 仅使用 7 位/字符,允许编码 128 个字符,而现代 UTF-8 最多使用 4 字节/字符。UTF-8 与 ASCII 兼容(因此任何 ASCII 编码的字符串都是有效的 UTF-8 字符串),但反之则不然。

显然,您的文件名包含非 ASCII 字符。默认情况下,python 希望将其读取为简单的 ASCII 编码字符串,发现一个非 ASCII 字符(它的第一位不是 0,因为它是 0xe2)并说,'ascii' 编解码器无法解码位置 2 中的字节 0xe2:序数不在范围内(128)。

与 python 无关,但仍然是我最喜欢的关于编码的教程:

http://hektor.umcs.lublin.pl/~mikosmul/computing/articles/linux-unicode.html

于 2012-09-13T15:18:24.507 回答