tl; dr / perbaikan cepat
- Jangan mendekode / menyandikan mau tak mau
- Jangan menganggap string Anda dikodekan UTF-8
- Cobalah untuk mengubah string ke string Unicode sesegera mungkin dalam kode Anda
- Perbaiki lokal Anda: Bagaimana mengatasi UnicodeDecodeError di Python 3.6?
- Jangan tergoda untuk menggunakan
reload
peretasan cepat
Unicode Zen dengan Python 2.x - Versi Panjang
Tanpa melihat sumbernya, sulit untuk mengetahui akar masalahnya, jadi saya harus berbicara secara umum.
UnicodeDecodeError: 'ascii' codec can't decode byte
umumnya terjadi ketika Anda mencoba untuk mengubah Python 2.x str
yang berisi non-ASCII ke string Unicode tanpa menentukan pengkodean dari string asli.
Singkatnya, string Unicode adalah tipe string Python yang sepenuhnya terpisah yang tidak mengandung pengodean apa pun. Mereka hanya memegang kode titik Unicode dan karena itu dapat menampung titik Unicode dari seluruh spektrum. String berisi teks yang disandikan, beit UTF-8, UTF-16, ISO-8895-1, GBK, Big5 dll. String di-decode ke Unicode dan Unicode di -encode ke string . File dan data teks selalu ditransfer dalam string yang disandikan.
Penulis modul Markdown mungkin menggunakan unicode()
(di mana pengecualian dilemparkan) sebagai gerbang kualitas ke sisa kode - itu akan mengkonversi ASCII atau membungkus kembali string Unicodes yang ada ke string Unicode baru. Penulis penurunan harga tidak dapat mengetahui pengkodean string yang masuk sehingga akan bergantung pada Anda untuk mendekode string ke string Unicode sebelum melewati Markdown.
String Unicode dapat dideklarasikan dalam kode Anda menggunakan u
awalan ke string. Misalnya
>>> my_u = u'my ünicôdé strįng'
>>> type(my_u)
<type 'unicode'>
String Unicode juga dapat berasal dari file, database, dan modul jaringan. Ketika ini terjadi, Anda tidak perlu khawatir tentang pengkodean.
Gotcha
Konversi dari str
ke Unicode dapat terjadi bahkan ketika Anda tidak secara eksplisit menelepon unicode()
.
Skenario berikut menyebabkan UnicodeDecodeError
pengecualian:
# Explicit conversion without encoding
unicode('€')
# New style format string into Unicode string
# Python will try to convert value string to Unicode first
u"The currency is: {}".format('€')
# Old style format string into Unicode string
# Python will try to convert value string to Unicode first
u'The currency is: %s' % '€'
# Append string to Unicode
# Python will try to convert string to Unicode first
u'The currency is: ' + '€'
Contohnya
Dalam diagram berikut, Anda dapat melihat bagaimana kata café
tersebut dikodekan dalam pengkodean "UTF-8" atau "Cp1252" tergantung pada jenis terminal. Dalam kedua contoh, caf
hanya ascii biasa. Dalam UTF-8, é
dikodekan menggunakan dua byte. Dalam "Cp1252", é adalah 0xE9 (yang juga merupakan nilai titik Unicode (bukan kebetulan)). Yang benar decode()
dipanggil dan konversi ke Python Unicode berhasil:
Dalam diagram ini, decode()
dipanggil dengan ascii
(yang sama dengan memanggil unicode()
tanpa diberikan pengkodean). Karena ASCII tidak dapat memuat byte lebih dari 0x7F
, ini akan menghasilkan UnicodeDecodeError
pengecualian:
Sandwich Unicode
Ini praktik yang baik untuk membentuk sandwich Unicode dalam kode Anda, tempat Anda mendekode semua data yang masuk ke string Unicode, bekerja dengan Unicode, lalu menyandikan ke str
saat keluar. Ini menyelamatkan Anda dari khawatir tentang pengkodean string di tengah kode Anda.
Input / Dekode
Kode sumber
Jika Anda perlu memanggang non-ASCII ke dalam kode sumber Anda, cukup buat string Unicode dengan awalan string dengan a u
. Misalnya
u'Zürich'
Untuk mengizinkan Python mendekode kode sumber Anda, Anda perlu menambahkan header pengodean untuk cocok dengan pengodean sebenarnya dari file Anda. Misalnya, jika file Anda dikodekan sebagai 'UTF-8', Anda akan menggunakan:
# encoding: utf-8
Ini hanya diperlukan ketika Anda memiliki non-ASCII dalam kode sumber Anda .
File
Biasanya data non-ASCII diterima dari file. The io
modul menyediakan TextWrapper yang menerjemahkan file Anda dengan cepat, menggunakan diberi encoding
. Anda harus menggunakan penyandian yang benar untuk file - tidak dapat dengan mudah ditebak. Misalnya, untuk file UTF-8:
import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
my_unicode_string = my_file.read()
my_unicode_string
maka akan cocok untuk diteruskan ke Penurunan harga. Jika a UnicodeDecodeError
dari read()
baris, maka Anda mungkin menggunakan nilai penyandian yang salah.
File CSV
Modul Python 2.7 CSV tidak mendukung karakter non-ASCII 😩. Namun, bantuan ada di tangan, dengan https://pypi.python.org/pypi/backports.csv .
Gunakan seperti di atas tetapi berikan file yang dibuka itu:
from backports import csv
import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
for row in csv.reader(my_file):
yield row
Basis data
Sebagian besar driver database Python dapat mengembalikan data dalam Unicode, tetapi biasanya memerlukan sedikit konfigurasi. Selalu gunakan string Unicode untuk kueri SQL.
MySQL
Dalam string koneksi tambahkan:
charset='utf8',
use_unicode=True
Misalnya
>>> db = MySQLdb.connect(host="localhost", user='root', passwd='passwd', db='sandbox', use_unicode=True, charset="utf8")
PostgreSQL
Menambahkan:
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)
HTTP
Halaman web dapat dikodekan dalam hampir semua pengkodean. The Content-type
header harus berisi charset
lapangan untuk mengisyaratkan pengkodean. Konten kemudian dapat diterjemahkan secara manual terhadap nilai ini. Atau, Python-Requests mengembalikan Unicodes response.text
.
Secara manual
Jika Anda harus mendekode string secara manual, Anda bisa melakukannya my_string.decode(encoding)
, di mana encoding
pengkodean yang sesuai. Python 2.x codec yang didukung diberikan di sini: Penyandian Standar . Sekali lagi, jika Anda mendapatkannya UnicodeDecodeError
maka Anda mungkin mendapatkan pengkodean yang salah.
Daging sandwich
Bekerja dengan Unicodes seperti yang biasa Anda lakukan strs.
Keluaran
stdout / pencetakan
print
menulis melalui aliran stdout. Python mencoba mengonfigurasi enkoder pada stdout sehingga Unicodes dikodekan ke enkode konsol. Misalnya, jika shell Linux locale
adalah en_GB.UTF-8
, output akan dikodekan ke UTF-8
. Di Windows, Anda akan dibatasi untuk halaman kode 8bit.
Konsol yang dikonfigurasi secara tidak benar, seperti lokal yang korup, dapat menyebabkan kesalahan cetak yang tidak terduga. PYTHONIOENCODING
variabel lingkungan dapat memaksa pengodean untuk stdout.
File
Sama seperti input, io.open
dapat digunakan untuk secara transparan mengkonversi Unicodes ke string byte yang dikodekan.
Basis data
Konfigurasi yang sama untuk membaca akan memungkinkan Unicodes ditulis secara langsung.
Python 3
Python 3 tidak lebih Unicode mampu daripada Python 2.x, namun sedikit kurang bingung pada topik. Misalnya biasa str
sekarang menjadi string Unicode dan yang lama str
sekarang bytes
.
Pengkodean default adalah UTF-8, jadi jika Anda .decode()
byte string tanpa memberikan pengkodean, Python 3 menggunakan pengkodean UTF-8. Ini mungkin memperbaiki 50% masalah Unicode orang.
Selanjutnya, open()
beroperasi dalam mode teks secara default, sehingga mengembalikan diterjemahkan str
(Unicode). Pengkodean berasal dari lokal Anda, yang cenderung UTF-8 pada sistem Un * x atau halaman kode 8-bit, seperti windows-1251, pada kotak Windows.
Mengapa Anda tidak harus menggunakannya sys.setdefaultencoding('utf8')
Ini adalah hack jahat (ada alasan Anda harus menggunakan reload
) yang hanya akan menutupi masalah dan menghambat migrasi Anda ke Python 3.x. Pahami masalahnya, perbaiki akar penyebabnya dan nikmati Unicode zen. Lihat Mengapa kita TIDAK menggunakan sys.setdefaultencoding ("utf-8") dalam skrip py? untuk keterangan lebih lanjut