tl; dr / correzione rapida
- Non decodificare / codificare volenti o nolenti
- Non dare per scontato che le tue stringhe siano codificate UTF-8
- Prova a convertire le stringhe in stringhe Unicode il prima possibile nel tuo codice
- Correggi le impostazioni internazionali: come risolvere UnicodeDecodeError in Python 3.6?
- Non essere tentato di usare
reload
hack rapidi
Unicode Zen in Python 2.x - La versione lunga
Senza vedere la fonte è difficile conoscere la causa principale, quindi dovrò parlare in generale.
UnicodeDecodeError: 'ascii' codec can't decode byte
generalmente si verifica quando si tenta di convertire un Python 2.x str
che contiene non ASCII in una stringa Unicode senza specificare la codifica della stringa originale.
In breve, le stringhe Unicode sono un tipo completamente separato di stringa Python che non contiene alcuna codifica. Possiedono solo codici punto Unicode e quindi possono contenere qualsiasi punto Unicode nell'intero spettro. Le stringhe contengono testo codificato, tra UTF-8, UTF-16, ISO-8895-1, GBK, Big5 ecc. Le stringhe vengono decodificate in Unicode e Unicode vengono codificate in stringhe . I file e i dati di testo vengono sempre trasferiti in stringhe codificate.
Gli autori del modulo Markdown probabilmente usano unicode()
(dove viene generata l'eccezione) come gate di qualità per il resto del codice: convertirà ASCII o avvolgerà nuovamente le stringhe Unicodes esistenti in una nuova stringa Unicode. Gli autori di Markdown non possono conoscere la codifica della stringa in arrivo, quindi si affideranno a te per decodificare le stringhe in stringhe Unicode prima di passare a Markdown.
Le stringhe Unicode possono essere dichiarate nel tuo codice usando il u
prefisso alle stringhe. Per esempio
>>> my_u = u'my ünicôdé strįng'
>>> type(my_u)
<type 'unicode'>
Le stringhe Unicode possono anche provenire da file, database e moduli di rete. Quando ciò accade, non devi preoccuparti della codifica.
Trabocchetti
La conversione da str
in Unicode può avvenire anche quando non chiami esplicitamente unicode()
.
I seguenti scenari causano UnicodeDecodeError
eccezioni:
# 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: ' + '€'
Esempi
Nel diagramma seguente, puoi vedere come la parola café
è stata codificata nella codifica "UTF-8" o "Cp1252" a seconda del tipo di terminale. In entrambi gli esempi, caf
è solo ascii normale. In UTF-8, é
è codificato usando due byte. In "Cp1252", é è 0xE9 (che è anche il valore del punto Unicode (non è una coincidenza)). decode()
Viene invocato il corretto e la conversione in Unicode Python ha esito positivo:
In questo diagramma, decode()
viene chiamato con ascii
(che equivale a chiamare unicode()
senza una codifica fornita). Poiché ASCII non può contenere byte maggiori di 0x7F
, ciò genererà UnicodeDecodeError
un'eccezione:
Il panino Unicode
È buona norma formare un sandwich Unicode nel codice, in cui decodifichi tutti i dati in arrivo in stringhe Unicode, lavori con Unicodes, quindi codifichi in str
uscita. Questo ti evita di preoccuparti della codifica delle stringhe nel mezzo del tuo codice.
Ingresso / Decodifica
Codice sorgente
Se devi inserire un codice non ASCII nel codice sorgente, crea semplicemente stringhe Unicode aggiungendo il prefisso a u
. Per esempio
u'Zürich'
Per consentire a Python di decodificare il tuo codice sorgente, dovrai aggiungere un'intestazione di codifica in modo che corrisponda alla codifica effettiva del tuo file. Ad esempio, se il tuo file fosse codificato come "UTF-8", utilizzeresti:
# encoding: utf-8
Ciò è necessario solo quando nel codice sorgente non è presente ASCII .
File
Di solito i dati non ASCII vengono ricevuti da un file. Il io
modulo fornisce un TextWrapper che decodifica il tuo file al volo, usando un dato encoding
. È necessario utilizzare la codifica corretta per il file: non è possibile indovinarlo facilmente. Ad esempio, per un 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
sarebbe quindi adatto per il passaggio a Markdown. Se UnicodeDecodeError
dalla read()
linea, probabilmente hai usato il valore di codifica sbagliato.
File CSV
Il modulo CSV Python 2.7 non supporta caratteri non ASCII 😩. L'aiuto è a portata di mano, tuttavia, con https://pypi.python.org/pypi/backports.csv .
Usalo come sopra ma passagli il file aperto:
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
Banche dati
La maggior parte dei driver di database Python può restituire dati in Unicode, ma in genere richiede una piccola configurazione. Utilizzare sempre stringhe Unicode per query SQL.
MySQL
Nella stringa di connessione aggiungi:
charset='utf8',
use_unicode=True
Per esempio
>>> db = MySQLdb.connect(host="localhost", user='root', passwd='passwd', db='sandbox', use_unicode=True, charset="utf8")
PostgreSQL
Inserisci:
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)
HTTP
Le pagine Web possono essere codificate praticamente in qualsiasi codifica. L' Content-type
intestazione deve contenere un charset
campo per suggerire la codifica. Il contenuto può quindi essere decodificato manualmente in base a questo valore. In alternativa, Python-Requests restituisce Unicodes in response.text
.
manualmente
Se devi decodificare manualmente le stringhe, puoi semplicemente fare my_string.decode(encoding)
, dov'è encoding
la codifica appropriata. I codec supportati da Python 2.x sono forniti qui: codifiche standard . Ancora una volta, se ottieni UnicodeDecodeError
allora probabilmente hai la codifica sbagliata.
La carne del panino
Lavora con Unicodes come faresti con le normali strs.
Produzione
stdout / stampa
print
scrive attraverso il flusso stdout. Python tenta di configurare un codificatore su stdout in modo che gli Unicode siano codificati nella codifica della console. Ad esempio, se un Linux shell di locale
è en_GB.UTF-8
, l'uscita viene codificato a UTF-8
. Su Windows, sarai limitato a una tabella codici a 8 bit.
Una console configurata in modo errato, come impostazioni internazionali danneggiate, può causare errori di stampa imprevisti. PYTHONIOENCODING
la variabile d'ambiente può forzare la codifica per stdout.
File
Proprio come l'input, io.open
può essere utilizzato per convertire in modo trasparente Unicode in stringhe di byte codificate.
Banca dati
La stessa configurazione per la lettura consentirà la scrittura diretta di Unicodes.
Python 3
Python 3 non è più compatibile con Unicode di Python 2.x, tuttavia è leggermente meno confuso sull'argomento. Ad esempio, il normale str
ora è una stringa Unicode e il vecchio str
ora bytes
.
La codifica predefinita è UTF-8, quindi se si utilizza .decode()
una stringa di byte senza fornire una codifica, Python 3 utilizza la codifica UTF-8. Questo probabilmente risolve il 50% dei problemi Unicode delle persone.
Inoltre, open()
funziona in modalità testo per impostazione predefinita, quindi restituisce decodificato str
(quelli Unicode). La codifica deriva dalle impostazioni internazionali, che tendono ad essere UTF-8 su sistemi Un * x o una tabella codici a 8 bit, come windows-1251, su scatole di Windows.
Perché non dovresti usare sys.setdefaultencoding('utf8')
È un brutto hack (c'è una ragione che devi usare reload
) che maschera solo i problemi e ostacola la tua migrazione a Python 3.x. Comprendi il problema, risolvi la causa principale e divertiti con Unicode zen. Vedi Perché NON dovremmo usare sys.setdefaultencoding ("utf-8") in uno script PY? per ulteriori dettagli