Python: il codec "ascii" non può decodificare byte


119

Sono veramente confuso. Ho provato a codificare ma l'errore ha detto can't decode....

>>> "你好".encode("utf8")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

So come evitare l'errore con il prefisso "u" sulla stringa. Mi chiedo solo perché l'errore è "impossibile decodificare" quando è stato chiamato encode. Cosa sta facendo Python sotto il cofano?

Risposte:


167
"你好".encode('utf-8')

encodeconverte un oggetto Unicode in un stringoggetto. Ma qui l'hai invocato su un stringoggetto (perché non hai la u). Quindi Python deve prima convertire il stringin un unicodeoggetto. Quindi fa l'equivalente di

"你好".decode().encode('utf-8')

Ma la decodifica non riesce perché la stringa non è ASCII valida. Ecco perché ricevi un reclamo per non essere in grado di decodificare.


50
Allora qual è la soluzione? Soprattutto se non ho una stringa letterale, ho solo un oggetto stringa.
Jon Tirsen

2
@ JonTirsen, non dovresti codificare un oggetto stringa. Un oggetto stringa è già codificato. Se è necessario modificare la codifica, è necessario decodificarla in una stringa Unicode e quindi codificarla come codifica desiderata.
Winston Ewert

20
Quindi, per affermarlo chiaramente dall'alto, puoi"你好".decode('utf-8').encode('utf-8')
deinonychusaur

5
@ WinstonEwert credo di essere stato confuso. Il business della codifica tende a lasciarmi eternamente confuso. Immagino che la mia confusione provenisse dal mio problema di non sapere se l'input è una stringa o una stringa Unicode e quale codifica potrebbe avere.
deinonychusaur

@deinonychusaur, sì ... ho capito.
Winston Ewert

53

Codifica sempre da Unicode a byte.
In questa direzione, puoi scegliere la codifica .

>>> u"你好".encode("utf8")
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> print _
你好

L'altro modo è decodificare da byte a Unicode.
In questa direzione, devi sapere qual è la codifica .

>>> bytes = '\xe4\xbd\xa0\xe5\xa5\xbd'
>>> print bytes
你好
>>> bytes.decode('utf-8')
u'\u4f60\u597d'
>>> print _
你好

Questo punto non può essere sottolineato abbastanza. Se vuoi evitare di giocare a "whack-a-mole" unicode, è importante capire cosa sta succedendo a livello di dati. Qui viene spiegato in un altro modo:

  • Un oggetto Unicode è già decodificato, non vorrai mai chiamarlo decode.
  • Un oggetto bytestring è già codificato, non vorrai mai chiamarlo encode.

Ora, vedendo .encodeuna stringa di byte, Python 2 cerca prima di convertirlo implicitamente in testo (un unicodeoggetto). Allo stesso modo, vedendo .decodesu una stringa Unicode, Python 2 tenta implicitamente di convertirla in byte (un stroggetto).

Queste conversioni implicite sono il motivo per cui puoi ottenere quando hai chiamato . È perché la codifica di solito accetta un parametro di tipo ; quando si riceve un parametro, c'è una decodifica implicita in un oggetto di tipo prima di ricodificarlo con un'altra codifica. Questa conversione sceglie un decodificatore "ascii" predefinito , fornendo l'errore di decodifica all'interno di un codificatore.UnicodeDecodeErrorencodeunicodestrunicode

In effetti, in Python 3 i metodi str.decodee bytes.encodenon esistono nemmeno. La loro rimozione è stato un tentativo [controverso] di evitare questa confusione comune.

... o qualsiasi altra codifica sys.getdefaultencoding()menzionata; di solito questo è "ascii"


Quindi vuoi dire che Python decodifica il bytestring prima di codificare?
thoslin

@thoslin esattamente, ho aggiunto ulteriori dettagli.
wim

Che cos'è _ e perché le tue dichiarazioni di stampa mancano di parentesi?
NoBugs

1
@NoBugs 1. nella REPL, _fa riferimento al valore precedente 2. perché questa è una domanda python-2.x.
wim

40

Puoi provare questo

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

O

Puoi anche provare a seguire

Aggiungi la seguente riga nella parte superiore del tuo file .py.

# -*- coding: utf-8 -*- 

8

Se stai usando Python <3, dovrai dire all'interprete che la tua stringa letterale è Unicode anteponendola au :

Python 2.7.2 (default, Jan 14 2012, 23:14:09) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> "你好".encode("utf8")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
>>> u"你好".encode("utf8")
'\xe4\xbd\xa0\xe5\xa5\xbd'

Ulteriori letture : Unicode HOWTO .


4
Se stai codificando una stringa, perché genera un errore di decodifica?
MxLDevs

3

Si utilizza u"你好".encode('utf8')per codificare una stringa Unicode. Ma se vuoi rappresentare "你好", dovresti decodificarlo. Proprio come:

"你好".decode("utf8")

Otterrai quello che vuoi. Forse dovresti saperne di più su codifica e decodifica.


3

Nel caso tu abbia a che fare con Unicode, a volte invece di encode('utf-8'), puoi anche provare a ignorare i caratteri speciali, ad es

"你好".encode('ascii','ignore')

o come something.decode('unicode_escape').encode('ascii','ignore')suggerito qui .

Non particolarmente utile in questo esempio, ma può funzionare meglio in altri scenari quando non è possibile convertire alcuni caratteri speciali.

In alternativa puoi considerare di sostituire un carattere particolare usandoreplace() .


1

Se stai avviando l'interprete python da una shell su Linux o sistemi simili (BSD, non sei sicuro di Mac), dovresti anche controllare la codifica predefinita per la shell.

Chiama locale charmapdalla shell (non dall'interprete Python) e dovresti vedere

[user@host dir] $ locale charmap
UTF-8
[user@host dir] $ 

Se non è così e vedi qualcos'altro, ad es

[user@host dir] $ locale charmap
ANSI_X3.4-1968
[user@host dir] $ 

Python erediterà (almeno in alcuni casi come nel mio) la codifica della shell e non sarà in grado di stampare (alcuni? Tutti?) Caratteri Unicode. La codifica predefinita di Python che vedi e controlli tramite sys.getdefaultencoding()e sys.setdefaultencoding()in questo caso viene ignorata.

Se scopri di avere questo problema, puoi risolverlo

[user@host dir] $ export LC_CTYPE="en_EN.UTF-8"
[user@host dir] $ locale charmap
UTF-8
[user@host dir] $ 

(Oppure, in alternativa, scegli la mappa dei tasti che desideri invece di en_EN.) Puoi anche modificare /etc/locale.conf(o qualunque file governa la definizione locale nel tuo sistema) per correggere questo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.