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
reloadhack 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 bytegeneralmente si verifica quando si tenta di convertire un Python 2.x strche 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 uprefisso 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 strin Unicode può avvenire anche quando non chiami esplicitamente unicode().
I seguenti scenari causano UnicodeDecodeErroreccezioni:
# 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à UnicodeDecodeErrorun'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 struscita. 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 iomodulo 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_stringsarebbe quindi adatto per il passaggio a Markdown. Se UnicodeDecodeErrordalla 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-typeintestazione deve contenere un charsetcampo 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'è encodingla codifica appropriata. I codec supportati da Python 2.x sono forniti qui: codifiche standard . Ancora una volta, se ottieni UnicodeDecodeErrorallora probabilmente hai la codifica sbagliata.
La carne del panino
Lavora con Unicodes come faresti con le normali strs.
Produzione
stdout / stampa
printscrive 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. PYTHONIOENCODINGla variabile d'ambiente può forzare la codifica per stdout.
File
Proprio come l'input, io.openpuò 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 strora è una stringa Unicode e il vecchio strora 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