Python - Der Codec 'ascii' kann kein Byte dekodieren

119

Ich bin wirklich verwirrt. Ich habe versucht zu codieren, aber der Fehler sagte 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)

Ich weiß, wie ich den Fehler mit dem Präfix "u" in der Zeichenfolge vermeiden kann. Ich frage mich nur, warum der Fehler "Kann nicht dekodieren" ist, als die Kodierung aufgerufen wurde. Was macht Python unter der Haube?

Thoslin
quelle

Antworten:

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

encodekonvertiert ein Unicode-Objekt in ein stringObjekt. Aber hier haben Sie es für ein stringObjekt aufgerufen (weil Sie das u nicht haben). Python muss also zuerst das stringin ein unicodeObjekt konvertieren . Also macht es das Äquivalent von

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

Die Dekodierung schlägt jedoch fehl, da die Zeichenfolge nicht gültig ist. Aus diesem Grund erhalten Sie eine Beschwerde darüber, dass Sie nicht dekodieren können.

Winston Ewert
quelle
50
Was ist die Lösung? Besonders wenn ich kein String-Literal habe, habe ich nur ein String-Objekt.
Jon Tirsen
2
@ JonTirsen, Sie sollten kein String-Objekt codieren. Ein String-Objekt ist bereits codiert. Wenn Sie die Codierung ändern müssen, müssen Sie sie in eine Unicode-Zeichenfolge decodieren und dann als gewünschte Codierung codieren.
Winston Ewert
20
"你好".decode('utf-8').encode('utf-8')
Um
5
@ WinstonEwert Ich glaube ich war verwirrt. Das Codierungsgeschäft neigt dazu, mich für immer verwirrt zu lassen. Ich schätze, meine Verwirrung kam von meinem eigenen Problem, nicht zu wissen, ob es sich bei der Eingabe um eine Zeichenfolge oder eine Unicode-Zeichenfolge handelt und welche Codierung sie möglicherweise hat.
Deinonychusaur
@deinonychusaur, ja ... das verstehe ich.
Winston Ewert
53

Codieren Sie immer von Unicode zu Bytes.
In dieser Richtung können Sie die Codierung auswählen .

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

Die andere Möglichkeit besteht darin, von Bytes in Unicode zu dekodieren.
In dieser Richtung müssen Sie die Codierung kennen .

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

Dieser Punkt kann nicht genug betont werden. Wenn Sie vermeiden möchten, Unicode "Whack-a-Mole" zu spielen, ist es wichtig zu verstehen, was auf Datenebene passiert. Hier wird es anders erklärt:

  • Ein Unicode-Objekt ist bereits dekodiert, Sie möchten es nie mehr aufrufen decode.
  • Ein bytestring-Objekt ist bereits codiert, Sie möchten es niemals aufrufen encode.

Wenn .encodePython 2 nun eine Byte-Zeichenfolge sieht , versucht es zunächst, sie implizit in Text (ein unicodeObjekt) zu konvertieren . In ähnlicher Weise .decodeversucht Python 2 beim Anzeigen einer Unicode-Zeichenfolge implizit, diese in Bytes (ein strObjekt) zu konvertieren .

Diese impliziten Konvertierungen sind der Grund, warum Sie erhalten können, wenn Sie angerufen haben . Dies liegt daran, dass die Codierung normalerweise einen Parameter vom Typ akzeptiert . Beim Empfang eines Parameters erfolgt eine implizite Dekodierung in ein Objekt vom Typ, bevor es mit einer anderen Codierung neu codiert wird. Bei dieser Konvertierung wird ein Standard-ASCII-Decoder † ausgewählt , der den Decodierungsfehler in einem Encoder anzeigt.UnicodeDecodeErrorencodeunicodestrunicode

Tatsächlich existieren in Python 3 die Methoden str.decodeund bytes.encodeexistieren nicht einmal. Ihre Entfernung war ein [kontroverser] Versuch, diese allgemeine Verwirrung zu vermeiden.

... oder was auch immer Codierung sys.getdefaultencoding()erwähnt; normalerweise ist dies 'ascii'

wim
quelle
Meinen Sie damit, dass Python den Bytestring vor dem Codieren dekodiert?
Thoslin
@thoslin genau, ich habe weitere Details hinzugefügt.
wim
Was ist _ und warum fehlen in Ihren Druckanweisungen Klammern?
NoBugs
1
@NoBugs 1. _bezieht sich in der REPL auf den vorherigen Wert 2., da dies eine Python-2.x-Frage ist.
wim
40

Sie können dies versuchen

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

Oder

Sie können auch versuchen, zu folgen

Fügen Sie die folgende Zeile oben in Ihre .py-Datei ein.

# -*- coding: utf-8 -*- 
Dadaso Zanzane
quelle
8

Wenn Sie Python <3 verwenden, müssen Sie dem Interpreter mitteilen, dass Ihr Zeichenfolgenliteral Unicode ist, indem Sie ihm Folgendes voranstellenu :

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'

Weiterführende Literatur : Unicode HOWTO .

Johnsyweb
quelle
4
Wenn Sie eine Zeichenfolge codieren, warum wird dann ein Decodierungsfehler ausgegeben?
MxLDevs
3

Sie verwenden u"你好".encode('utf8')diese Option, um eine Unicode-Zeichenfolge zu codieren. Aber wenn Sie darstellen möchten "你好", sollten Sie es dekodieren. So wie:

"你好".decode("utf8")

Sie werden bekommen, was Sie wollen. Vielleicht sollten Sie mehr über das Codieren und Decodieren erfahren.

Qingtian
quelle
3

Wenn Sie sich mit Unicode beschäftigen, können Sie manchmal encode('utf-8')auch versuchen, die Sonderzeichen zu ignorieren, z

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

oder wie something.decode('unicode_escape').encode('ascii','ignore')hier vorgeschlagen .

In diesem Beispiel nicht besonders nützlich, kann aber in anderen Szenarien besser funktionieren, wenn einige Sonderzeichen nicht konvertiert werden können.

Alternativ können Sie ein bestimmtes Zeichen durch ersetzenreplace() .

Kenorb
quelle
1

Wenn Sie den Python-Interpreter von einer Shell unter Linux oder ähnlichen Systemen starten (BSD, nicht sicher über Mac), sollten Sie auch die Standardcodierung für die Shell überprüfen.

Rufen Sie locale charmapvon der Shell aus (nicht vom Python-Interpreter) und Sie sollten sehen

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

Wenn dies nicht der Fall ist und Sie etwas anderes sehen, z

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

Python erbt (zumindest in einigen Fällen wie in meinem) die Codierung der Shell und kann keine (einige? Alle?) Unicode-Zeichen drucken. Pythons eigene Standardcodierung, die Sie über sys.getdefaultencoding()und sehen und steuernsys.setdefaultencoding() die in diesem Fall ignoriert wird.

Wenn Sie feststellen, dass Sie dieses Problem haben, können Sie es durch beheben

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

(Oder wählen Sie alternativ die gewünschte Keymap anstelle von en_EN.) Sie können auch bearbeiten /etc/locale.conf(oder die Datei, die die Gebietsschema-Definition in Ihrem System regelt), um dies zu korrigieren.

0Bereich
quelle