UnicodeDecodeError: 'ascii'コーデックは位置2のバイト0xd1をデコードできません:序数が範囲(128)にありません


107

非標準の文字が含まれている非常に大きなデータセットを操作しようとしています。ジョブの仕様に従って、Unicodeを使用する必要がありますが、困惑しています。(そして、おそらくそれをすべて間違っている。)

私は次を使用してCSVを開きます:

 15     ncesReader = csv.reader(open('geocoded_output.csv', 'rb'), delimiter='\t', quotechar='"')

次に、それを次のようにエンコードしようとします。

name=school_name.encode('utf-8'), street=row[9].encode('utf-8'), city=row[10].encode('utf-8'), state=row[11].encode('utf-8'), zip5=row[12], zip4=row[13],county=row[25].encode('utf-8'), lat=row[22], lng=row[23])

APIに送信する必要があるため、latとlng以外のすべてをエンコードしています。プログラムを実行してデータセットを解析して使用可能なものにすると、次のトレースバックが得られます。

Traceback (most recent call last):
  File "push_into_db.py", line 80, in <module>
    main()
  File "push_into_db.py", line 74, in main
    district_map = buildDistrictSchoolMap()
  File "push_into_db.py", line 32, in buildDistrictSchoolMap
    county=row[25].encode('utf-8'), lat=row[22], lng=row[23])
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 2: ordinal not in range(128)

私はpython 2.7.2を使用していることをお伝えしたいと思います。これはdjango 1.4でビルドされたアプリの一部です。私はこのトピックに関するいくつかの投稿を読みましたが、それらのどれも直接当てはまらないようです。どんな助けでも大歓迎です。

また、問題の原因となっている非標準文字の一部がÑであり、場合によってはÉであることも知りたい場合があります。


1
元のファイルのエンコーディングは何ですか?元のエンコーディングに従ってデコードしてから、utf 8に変換する必要があると思います
シャオ啸

回答:


152

UnicodeはUTF-8とは異なります。後者は前者の単なるエンコーディングです。

あなたはそれを間違った方法でやっています。あなたはされて読んで UTF-8 エンコードされたあなたがしなければならないので、データをデコードするユニコード文字列にUTF-8でエンコードされた文字列を。

だから置き換え.encode.decode(あなたの.CSVがUTF-8でエンコードされている場合)、およびそれが動作するはずです。

恥ずかしいことは何もありません。私は5人に3人のプログラマが最初はこれを理解するのに苦労したに違いない;)

更新:入力データがUTF-8エンコードされていない場合は.decode()、もちろん適切なエンコードにする必要があります。何も指定されていない場合、PythonはASCIIを想定します。これは明らかに非ASCII文字では失敗します。


1
エラーの理由は、PythonがデフォルトのエンコーディングであるASCIIから自動的にデコードして、指定したとおりにUTF-8にエンコードしようとしているためです。データは有効なASCIIではないため、機能しません。
agf

7
確かに、しかしそれがUTF8でエンコードされたデータ(私が推測しているように)である場合.decode('utf-8')は、トリックを実行する必要がありますか?
ch3ka

確かに、あなたはおそらく正しいです。この状況で特定のエラーが発生する理由を説明しました。
agf

1
パーフェクト!どうもありがとうございました。したがって、それは.decode( 'latin-1')であることがわかります-これは、問題を引き起こしていたのはbecauseであったため、理にかなっています。再び!ありがとうございました!
jelkimantis

あなたの解決策はいくつかのケースで機能しますが、これを使用すると、別のエラー「ascii」コーデックが位置2の文字u '\ xf1'をエンコードできません。序数が範囲外です(128)
Vikash Mishra

84

この行をコードに追加してください:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

5
`AttributeError:モジュール 'sys'に属性がない 'setdefaultencoding'はPython 3では機能しないようです
skjerns

ウットウット!これは私を助けました。
牧島

1
Python 2.7で動作します。reload(sys)が必要です。それ以外の場合は、setdefaultencodingにアクセスできません。
Yu Shen

1
それが、多くのSOの質問のうち、私にとってそれを機能させた唯一のものでした。本当にありがとう!
Freedo

名前「リロード」は定義されていません
Davide

28

Python 3ユーザー向け。できるよ

with open(csv_name_here, 'r', encoding="utf-8") as f:
    #some codes

フラスコでも動作します:)


1
ここで誰かを助けたのは初めてです。:)
Skrmnghrd

1
そして、あなたも私を助けました:)他のすべての答えはファイルの読み取りにうまくいきませんでした。今私はそれを書くためにもそれを修正する方法を見つける必要があります;)
user2194898

コードのリンクを送っていただけますか?私がお手伝いします
Skrmnghrd

9

エラーの主な理由は、Pythonが想定するデフォルトのエンコーディングがASCIIであることです。したがって、エンコード対象の文字列データにencode('utf8')ASCII範囲外の文字が含まれている場合(たとえば、 'hgvcj터파크387'のような文字列の場合)、文字列が予期されるエンコード形式ではないため、Pythonはエラーをスローします。

バージョン3.5より前のPythonバージョンを使用している場合、信頼できる修正は、Pythonが想定するデフォルトのエンコーディングを次のように設定することですutf8

import sys
reload(sys)
sys.setdefaultencoding('utf8')
name = school_name.encode('utf8')

このように、PythonはASCII範囲外の文字列内の文字を予測できます。

ただし、Pythonバージョン3.5以降を使用している場合、reload()関数は使用できないため、decode egを使用して修正する必要があります。

name = school_name.decode('utf8').encode('utf8')

あなたの答えと私の違いは何
ですか

1
より詳細な。因果関係の詳細が役立つことがよくあります。そして、あなたのコードは機能しますが、軽蔑は意図されていません。
Temi Fakunle 2017

1
リロードはPython 3で利用でき、インポートするだけです。IMP輸入リロードから
ニャー

@Meowですが、Python 3にはsys.setdefaultencodingはありません。したがって、互換性py2 \ py3のコンテキストでは、いくつかのチェックが行われ、おそらくsys.getdefaultencoding()が行われます。その件についてのアドバイスをいただければ幸いです。stackoverflow.com/questions/28127513/...
Konst54

2

Python 3ユーザーの場合:

エンコーディングを「ascii」から「latin1」に変更すると機能します。

また、以下のスニペットを使用して上位10000バイトを読み取ることにより、エンコーディングを自動的に見つけることもできます。

import chardet  
with open("dataset_path", 'rb') as rawdata:  
            result = chardet.detect(rawdata.read(10000))  
print(result)

2

コンピュータに間違ったロケールが設定されていました。

私が最初にやった

>>> import locale
>>> locale.getpreferredencoding(False)
'ANSI_X3.4-1968'

locale.getpreferredencoding(False)open()エンコーディングを指定しない場合に呼び出される関数です。出力はになります'UTF-8'が、この場合は、ASCIIのバリアントです

次に、bashコマンドを実行して、localeこの出力を取得しました

$ locale
LANG=
LANGUAGE=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

そのため、デフォルトのUbuntuロケールを使用していたため、PythonはファイルをUTF-8ではなくASCIIとして開きました。私がしなければならなかった私のロケールを設定しますen_US.UTF-8

sudo apt install locales 
sudo locale-gen en_US en_US.UTF-8    
sudo dpkg-reconfigure locales

システム全体でロケールを変更できない場合は、次のようにすべてのPythonコードを呼び出すことができます。

PYTHONIOENCODING="UTF-8" python3 ./path/to/your/script.py

またはする

export PYTHONIOENCODING="UTF-8"

それを実行するシェルに設定します。


1

証明書の作成または更新中にcertbotを実行中にこの問題が発生した場合は、次の方法を使用してください

grep -r -P '[^\x00-\x7f]' /etc/apache2 /etc/letsencrypt /etc/nginx

このコマンドは、コメント内の1つの.confファイルで問題のある文字「 ´」を見つけました。それを削除し(コメントを好きなように編集できます)、nginxを再ロードすると、すべてが再び機能します。

ソース:https : //github.com/certbot/certbot/issues/5236


0

または、Unicodeテキストの場合、Pythonでテキストを処理するときは、Unicodeであることに注意してください。

text=u'unicode text'代わりに単に設定してくださいtext='unicode text'

これは私の場合にはうまくいきました。


0

緯度と経度が長いため、エンコーディングはUTF 16で開きます。

with open(csv_name_here, 'r', encoding="utf-16") as f:

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.