UnicodeDecodeError: codec 'ascii' tidak dapat mendekode byte 0xd1 di posisi 2: ordinal tidak dalam jangkauan (128)

107

Saya mencoba bekerja dengan kumpulan data yang sangat besar yang memiliki beberapa karakter non-standar di dalamnya. Saya perlu menggunakan unicode, sesuai spesifikasi pekerjaan, tetapi saya bingung. (Dan sangat mungkin melakukan semuanya dengan salah.)

Saya membuka CSV menggunakan:

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

Kemudian, saya mencoba untuk menyandikannya dengan:

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])

Saya mengkodekan semuanya kecuali lat dan lng karena itu perlu dikirim ke API. Ketika saya menjalankan program untuk mengurai dataset menjadi apa yang dapat saya gunakan, saya mendapatkan Traceback berikut.

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)

Saya rasa saya harus memberi tahu Anda bahwa saya menggunakan python 2.7.2, dan ini adalah bagian dari aplikasi yang dibangun di atas django 1.4. Saya telah membaca beberapa posting tentang topik ini, tetapi tidak satupun dari mereka yang tampaknya secara langsung berlaku. Bantuan apa pun akan sangat dihargai.

Anda mungkin juga ingin mengetahui bahwa beberapa karakter non-standar yang menyebabkan masalah adalah Ñ dan mungkin É.

jelkimantis
sumber
1
Apa pengkodean file asli Anda? Saya pikir Anda harus mendekodekannya sesuai dengan pengkodean asli dan kemudian mengonversinya ke utf 8
xiao 啸
kemungkinan duplikat Encoding memberikan "'ascii' codec tidak dapat menyandikan karakter… ordinal tidak dalam jangkauan (128)" [Ed .: dan sekitar satu juta lainnya, saya yakin.]
Karl Knechtel

Jawaban:

152

Unicode tidak sama dengan UTF-8. Yang terakhir hanyalah penyandian untuk yang pertama.

Anda melakukannya dengan cara yang salah. Anda membaca UTF-8- dikodekan data, sehingga Anda harus decode UTF-8-encoded String ke dalam string unicode.

Jadi ganti saja .encodedengan.decode , dan itu akan berfungsi (jika .csv Anda dikodekan UTF-8).

Tidak ada yang memalukan. Saya yakin 3 dari 5 pemrogram mengalami kesulitan pada awalnya untuk memahami ini, jika tidak lebih;)

Pembaruan: Jika data input Anda tidak dikodekan UTF-8, maka Anda harus .decode()dengan pengkodean yang sesuai, tentu saja. Jika tidak ada yang diberikan, python mengasumsikan ASCII, yang jelas gagal pada karakter non-ASCII.

ch3ka
sumber
1
Alasan kesalahannya adalah karena Python mencoba untuk secara otomatis mendekodekannya dari pengkodean default, ASCII, sehingga kemudian dapat menyandikannya seperti yang dia tentukan, ke UTF-8. Karena datanya bukan ASCII yang valid, itu tidak berfungsi.
agf
7
tentu, tetapi jika itu adalah data yang dikodekan UTF8- (seperti yang saya duga), maka .decode('utf-8')harus melakukan trik, bukan?
ch3ka
Tentu, Anda mungkin benar. Saya baru saja menjelaskan mengapa Anda mendapatkan kesalahan khusus itu dalam situasi ini.
agf
1
Sempurna! Terima kasih banyak. Jadi ternyata itu .decode ('latin-1') - ini masuk akal karena Ñ yang memberi saya masalah. Lagi! Terima kasih!
jelkimantis
Solusi Anda berfungsi untuk beberapa kasus, tetapi jika saya menggunakan ini maka saya mendapatkan kesalahan lain 'ascii' codec tidak dapat menyandikan karakter u '\ xf1' di posisi 2: ordinal tidak dalam jangkauan (128)
Vikash Mishra
84

Cukup tambahkan baris ini ke kode Anda:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')
khelili miliana
sumber
5
`AttributeError: module 'sys' tidak memiliki atribut 'setdefaultencoding' tampaknya tidak berfungsi dengan Python 3
skjerns
Woot woot! Ini membantu saya.
Shougo Makishima
1
Ini berfungsi untuk Python 2.7 saya, catatan, muat ulang (sys) diperlukan, jika tidak, setdefaultencoding tidak akan dapat diakses.
Yu Shen
1
Itulah satu-satunya hal yang membuatnya berhasil bagi saya dari banyak pertanyaan SO. Terima kasih banyak!
Freedo
nama 'reload' tidak ditentukan
Davide
28

untuk pengguna Python 3. Anda dapat melakukan

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

ini bekerja dengan flask juga :)

Skrmnghrd
sumber
1
Ini pertama kalinya aku membantu seseorang lewat sini. merasa senang mengetahui saya membantu :)
Skrmnghrd
1
Dan Anda juga membantu saya :) Semua jawaban lainnya tidak berfungsi untuk membaca file. Sekarang saya perlu mencari tahu cara memperbaikinya juga untuk menulis;)
user2194898
dapatkah Anda mengirimkan saya tautan kode Anda? Saya akan mencoba membantu
Skrmnghrd
9

Alasan utama kesalahan ini adalah pengkodean default yang diasumsikan oleh python adalah ASCII. Oleh karena itu, jika data string akan dikodekan olehencode('utf8') berisi karakter yang berada di luar rentang ASCII misalnya untuk string seperti 'hgvcj 터 파크 387', python akan menampilkan kesalahan karena string tersebut tidak dalam format pengkodean yang diharapkan.

Jika Anda menggunakan versi python sebelum versi 3.5, perbaikan yang dapat diandalkan adalah menyetel pengkodean default yang diasumsikan oleh python ke utf8:

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

Dengan cara ini python akan dapat mengantisipasi karakter dalam string yang berada di luar rentang ASCII.

Namun, jika Anda menggunakan python versi 3.5 atau lebih tinggi, fungsi reload () tidak tersedia, jadi Anda harus memperbaikinya menggunakan decode mis.

name = school_name.decode('utf8').encode('utf8')
Temi Fakunle
sumber
apa perbedaan antara jawabanmu dan milikku
khelili miliana
1
Lebih detail. Orang sering menemukan detail kausal bermanfaat. Dan kode Anda berfungsi btw, tidak ada pengurangan yang dimaksudkan.
Temi Fakunle
1
reload tersedia dengan Python 3 Anda hanya perlu mengimpornya. dari imp import reload
Meong
@ Meow tetapi tidak ada sys.setdefaultencoding di Python 3. Jadi dalam konteks kompatibilitas py2 \ py3 beberapa pemeriksaan akan dilakukan, sys.getdefaultencoding () mungkin. Akan sangat menghargai nasihat tentang masalah itu. stackoverflow.com/questions/28127513/…
Konst54
2

Untuk pengguna Python 3:

mengubah pengkodean dari 'ascii' menjadi 'latin1' berfungsi.

Selain itu, Anda dapat mencoba menemukan pengkodean secara otomatis dengan membaca 10.000 byte teratas menggunakan cuplikan di bawah ini:

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

Komputer saya memiliki lokasi yang salah.

Saya pertama kali melakukannya

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

locale.getpreferredencoding(False)adalah fungsi yang dipanggil open()saat Anda tidak menyediakan encoding . Outputnya seharusnya 'UTF-8', tetapi dalam hal ini adalah beberapa varian ASCII .

Lalu saya menjalankan perintah bash localedan mendapatkan output ini

$ 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=

Jadi, saya menggunakan lokal Ubuntu default, yang menyebabkan Python membuka file sebagai ASCII, bukan UTF-8. Saya harus menyetel lokal saya keen_US.UTF-8

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

Jika Anda tidak dapat mengubah sistem lokal secara luas, Anda dapat memanggil semua kode Python Anda seperti ini:

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

atau lakukan

export PYTHONIOENCODING="UTF-8"

untuk mengaturnya di shell tempat Anda menjalankannya.

Boris
sumber
1

jika Anda mendapatkan masalah ini saat menjalankan certbot saat membuat atau memperbarui sertifikat, silakan gunakan metode berikut

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

Perintah itu menemukan karakter yang melanggar "´" dalam satu file .conf di komentar. Setelah menghapusnya (Anda dapat mengedit komentar sesuai keinginan) dan memuat ulang nginx, semuanya berfungsi kembali.

Sumber: https://github.com/certbot/certbot/issues/5236

Anish Varghese
sumber
0

Atau ketika Anda berurusan dengan teks dengan Python jika itu adalah teks Unicode, catat itu adalah Unicode.

Setel text=u'unicode text'saja text='unicode text'.

Ini berhasil dalam kasus saya.

prosti
sumber
0

terbuka dengan encoding UTF 16 karena lat dan long.

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

Ia bekerja dengan hanya mengambil argumen 'rb' baca biner daripada 'r' baca

Jose Garcia-Uceda
sumber