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違うかもしれないと思ったのですが、出力を見るとそれが原因ではないと思います。誰か説明してくれませんか?ありがとう!

バージョン:

  • OS: 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.encode-temp.json

["™"]
4

2 に答える 2

4

JSON.load()関数は、未加工のバイトではなく、Unicode データを想定しています。Python は、デフォルトのコーデック (この場合は ASCII) を使用してバイト文字列を Unicode 文字列に自動的にデコードしようとしますが、失敗します。UTF-8コーデックでファイルを開くことにより、Python は明示的な変換を行います。open()関数を参照してください。次のように述べています。

テキスト モードでは、エンコーディングが指定されていない場合、使用されるエンコーディングはプラットフォームに依存します。

使用されるエンコーディングは、次のように決定されます。

  • os.device_encoding()端末エンコーディングがあるかどうかを確認してください。
  • コードを実行する環境に応じてlocale.getpreferredencoding()functionを使用します。do_setlocaleその関数の は に設定されFalseます。
  • 'ASCII'両方のメソッドが を返した場合、デフォルトとして使用しますNone

これはすべて 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 文字列とバイト文字列の違い、およびエンコーディングについてすべて説明しています。この件に関するもう 1 つの重要な記事は、Joel Spolsky のAbsolute Minimum Unicode knowledge articleです。

于 2012-09-13T15:03:54.087 に答える
0

Python 2.x には文字列と Unicode 文字列があります。基本文字列は ASCII でエンコードされます。ASCII は 128 文字をエンコードできる 7 ビット/文字のみを使用しますが、最新の UTF-8 は最大 4 バイト/文字を使用します。UTF-8 は ASCII と互換性がありますが (ASCII でエンコードされた文字列はすべて有効な UTF-8 文字列になります)、その逆はありません。

ファイル名に ASCII 以外の文字が含まれているようです。そして、Python はデフォルトで単純な ASCII エンコード文字列としてそれを読み込もうとし、非 ASCII 文字 (最初のビットは 0xe2 であるため 0 ではありません) を検出し、「ascii」コーデックは位置 2 のバイト 0xe2 をデコードできないと言います:範囲外の序数 (128)。

Python とは何の関係もありませんが、エンコーディングに関する私のお気に入りのチュートリアル:

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

于 2012-09-13T15:18:24.507 に答える