[python] Wie zu beheben: "UnicodeDecodeError: 'Ascii' Codec kann Byte nicht dekodieren"


Answers

tl; dr

  • Willy Nilly nicht dekodieren / kodieren
  • Gehen Sie nicht davon aus, dass Ihre Zeichenfolgen UTF-8-codiert sind
  • Versuchen Sie, Zeichenfolgen in Unicode-Zeichenfolgen so bald wie möglich in Ihrem Code zu konvertieren

Python 2.x - Die lange Version

Ohne die Quelle zu sehen, ist es schwierig, die Ursache zu kennen, also muss ich allgemein sprechen.

UnicodeDecodeError: 'ascii' codec can't decode byte passiert in der Regel, wenn Sie versuchen, eine Python 2.x str , die Nicht-ASCII enthält, in eine Unicode-Zeichenfolge zu konvertieren, ohne die Codierung der ursprünglichen Zeichenfolge anzugeben.

Kurz gesagt, Unicode-Strings sind ein ganz eigener Typ von Python-Strings, der keine Codierung enthält. Sie enthalten nur Unicode- Punktcodes und können daher jeden Unicode-Punkt aus dem gesamten Spektrum aufnehmen. Zeichenfolgen enthalten kodierten Text, BEIT UTF-8, UTF-16, ISO-8895-1, GBK, Big5 usw. Zeichenfolgen werden in Unicode dekodiert und Unicodes werden in Zeichenfolgen codiert . Dateien und Textdaten werden immer in codierten Strings übertragen.

Die Autoren des Markdown-Moduls verwenden wahrscheinlich unicode() (wo die Ausnahme ausgelöst wird) als Qualitätsgatter für den Rest des Codes - es konvertiert ASCII oder umschließt bestehende Unicodes-Zeichenfolgen in eine neue Unicode-Zeichenfolge. Die Markdown-Autoren können die Codierung der eingehenden Zeichenfolge nicht kennen. Daher müssen Sie Zeichenfolgen in Unicode-Zeichenfolgen dekodieren, bevor Sie sie an Markdown übergeben.

Unicode-Zeichenfolgen können in Ihrem Code mit dem u Präfix zu Zeichenfolgen deklariert werden. Z.B

>>> my_u = u'my ünicôdé strįng'
>>> type(my_u)
<type 'unicode'>

Unicode-Strings können auch aus Dateien, Datenbanken und Netzwerkmodulen stammen. In diesem Fall müssen Sie sich keine Gedanken über die Codierung machen.

Gotchas

Die Konvertierung von str in Unicode kann auch dann erfolgen, wenn Sie nicht explizit unicode() aufrufen.

Die folgenden Szenarien verursachen UnicodeDecodeError Ausnahmen:

# 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: ' + '€'         

Beispiele

In der folgenden Abbildung können Sie sehen, wie das Wort café je nach Terminaltyp in der Codierung "UTF-8" oder "Cp1252" codiert wurde. In beiden Beispielen ist caf nur normal ascii. In UTF-8 wird é mit zwei Bytes codiert. In "Cp1252" ist é 0xE9 (was auch der Unicode-Punktwert ist (es ist kein Zufall)). Die korrekte decode() wird aufgerufen und die Konvertierung in einen Python-Unicode ist erfolgreich:

In diesem Diagramm wird decode() mit ascii aufgerufen (was dem Aufruf von unicode() ohne dass eine Codierung angegeben ist). Da ASCII keine Bytes größer als 0x7F enthalten kann, UnicodeDecodeError dies eine UnicodeDecodeError Ausnahme aus:

Das Unicode-Sandwich

Es empfiehlt sich, in Ihrem Code ein Unicode-Sandwich zu bilden, in dem Sie alle eingehenden Daten in Unicode-Strings decodieren, mit Unicodes arbeiten und dann auf dem Weg nach außen in Strings codieren. Dies erspart Ihnen die Sorge um die Codierung von Zeichenfolgen in der Mitte Ihres Codes.

Eingabe / Decodierung

Quellcode

Wenn Sie Nicht-ASCII-Code in Ihren Quellcode brennen müssen, erstellen Sie Unicode-Zeichenfolgen, indem Sie der Zeichenfolge ein u . Z.B

u'Zürich'

Damit Python Ihren Quellcode dekodieren kann, müssen Sie einen Kodierungsheader hinzufügen, der der tatsächlichen Kodierung Ihrer Datei entspricht. Wenn Ihre Datei beispielsweise als 'UTF-8' codiert wurde, würden Sie Folgendes verwenden:

# encoding: utf-8

Dies ist nur notwendig, wenn Sie nicht-ASCII in Ihrem Quellcode haben .

Dateien

Normalerweise werden Nicht-ASCII-Daten von einer Datei empfangen. Das io Modul bietet einen TextWrapper, der Ihre Datei mit einer bestimmten encoding dekodiert. Sie müssen die korrekte Kodierung für die Datei verwenden - es kann nicht leicht erraten werden. Zum Beispiel für eine UTF-8-Datei:

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 wäre dann zum Übergeben an Markdown geeignet. Wenn ein UnicodeDecodeError von der read() Zeile stammt, dann haben Sie wahrscheinlich den falschen Kodierungswert verwendet.

CSV-Dateien

Das Python 2.7 CSV-Modul unterstützt keine Nicht-ASCII-Zeichen 😩. Hilfe gibt es jedoch mit https://pypi.python.org/pypi/backports.csv .

Verwenden Sie es wie oben, aber übergeben Sie die geöffnete Datei an es:

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

Datenbanken

Die meisten Python-Datenbanktreiber können Daten in Unicode zurückgeben, erfordern jedoch normalerweise eine kleine Konfiguration. Verwenden Sie immer Unicode-Zeichenfolgen für SQL-Abfragen.

MySQL

Fügen Sie in der Verbindungszeichenfolge Folgendes hinzu:

charset='utf8',
use_unicode=True
PostgreSQL

Hinzufügen:

psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)

HTTP

Webseiten können in fast jeder Kodierung kodiert werden. Der Content-type Header sollte ein charset enthalten, um auf die Codierung charset . Der Inhalt kann dann manuell gegen diesen Wert dekodiert werden. Alternativ dazu gibt Python-Requests Unicodes in response.text .

Manuell

Wenn Sie Strings manuell dekodieren müssen, können Sie einfach my_string.decode(encoding) , wobei encoding die richtige Codierung ist. Von Python 2.x unterstützte Codecs sind hier aufgeführt: Standard Encodings . Wenn Sie UnicodeDecodeError erhalten, UnicodeDecodeError Sie wahrscheinlich die falsche Codierung.

Das Fleisch des Sandwiches

Arbeiten Sie mit Unicodes wie normale Strings.

Ausgabe

stdout / Drucken

print schreibt durch den Stdout-Stream. Python versucht, einen Encoder auf stdout zu konfigurieren, so dass Unicodes in die Codierung der Konsole codiert werden. Wenn beispielsweise das locale einer Linux-Shell en_GB.UTF-8 lautet, wird die Ausgabe in UTF-8 codiert. Unter Windows sind Sie auf eine 8-Bit-Codepage beschränkt.

Eine falsch konfigurierte Konsole, z. B. eine beschädigte Ländereinstellung, kann zu unerwarteten Druckfehlern führen. Umgebungsvariable PYTHONIOENCODING kann die Codierung für stdout erzwingen.

Dateien

Genau wie Eingabe kann io.open verwendet werden, um Unicodes transparent in codierte Byte-Strings umzuwandeln.

Datenbank

Die gleiche Konfiguration für das Lesen ermöglicht das direkte Schreiben von Unicodes.

Python 3

Python 3 ist nicht mehr Unicode-fähig wie Python 2.x, aber die reguläre str ist nun eine Unicode-Zeichenkette und die alte str ist jetzt bytes .

Die Standardcodierung ist nun UTF-8. Wenn Sie also .decode() eine .decode() ohne Angabe einer Codierung verwenden, verwendet Python 3 die UTF-8-Codierung. Dies behebt wahrscheinlich 50% der Unicode-Probleme von Menschen.

Außerdem arbeitet open() standardmäßig im Textmodus und gibt decodierte str (Unicode-Einsen) zurück. Die Codierung wird von Ihrem Gebietsschema abgeleitet, das auf Un * x-Systemen tendenziell UTF-8 oder auf Windows-Feldern eine 8-Bit-Codepage wie Windows-1251 ist.

Question
as3:~/ngokevin-site# nano content/blog/20140114_test-chinese.mkd
as3:~/ngokevin-site# wok
Traceback (most recent call last):
File "/usr/local/bin/wok", line 4, in
Engine()
File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 104, in init
self.load_pages()
File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 238, in load_pages
p = Page.from_file(os.path.join(root, f), self.options, self, renderer)
File "/usr/local/lib/python2.7/site-packages/wok/page.py", line 111, in from_file
page.meta['content'] = page.renderer.render(page.original)
File "/usr/local/lib/python2.7/site-packages/wok/renderers.py", line 46, in render
return markdown(plain, Markdown.plugins)
File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 419, in markdown
return md.convert(text)
File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 281, in convert
source = unicode(source)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 1: ordinal not in range(128). -- Note: Markdown only accepts unicode input!

Wie man es repariert?

In einigen anderen statischen Blog-Apps auf Python-Basis kann chinesische Post erfolgreich veröffentlicht werden. Wie diese App: http://github.com/vrypan/bucket3 . In meiner Website http://bc3.brite.biz/ kann chinesische Post erfolgreich veröffentlicht werden.




Ich habe versucht, die folgende Fehlermeldung zu lösen:

unicodedecodeerror: 'ascii' Codec kann Byte 0xe2 an Position 5454 nicht dekodieren: Ordnungszahl nicht im Bereich (128)

Ich habe es endlich behoben, indem ich 'encoding' angegeben habe:

f = open('../glove/glove.6B.100d.txt', encoding="utf-8")

Ich wünschte, es könnte dir auch helfen.




In einem Django (1.9.10) / Python 2.7.5 Projekt habe ich häufige UnicodeDecodeError Ausnahmen; hauptsächlich, wenn ich versuche, Unicode-Strings dem Logging zuzuführen. Ich habe eine Hilfsfunktion für beliebige Objekte erstellt, die im Grunde genommen in 8-Bit-ASCII-Strings formatiert werden und alle Zeichen, die nicht in der Tabelle enthalten sind, durch '?' Ersetzen. Ich denke, es ist nicht die beste Lösung, aber da die Standardcodierung ascii ist (und ich will es nicht ändern), wird es tun:

def encode_for_logging(c, encoding='ascii'):
    if isinstance(c, basestring):
        return c.encode(encoding, 'replace')
    elif isinstance(c, Iterable):
        c_ = []
        for v in c:
            c_.append(encode_for_logging(v, encoding))
        return c_
    else:
        return encode_for_logging(unicode(c))
`




Ich finde das Beste ist, immer in Unicode zu konvertieren - aber das ist schwer zu erreichen, weil man in der Praxis jedes Argument überprüfen und in jede Funktion und Methode umwandeln muss, die man schreibt, die irgendeine Art von String-Verarbeitung beinhaltet.

Also kam ich zu dem folgenden Ansatz, um entweder Unicodes oder Byte-Strings von beiden Eingaben zu garantieren. Kurz gesagt, fügen Sie folgende lambdas ein und verwenden Sie sie :

# guarantee unicode string
_u = lambda t: t.decode('UTF-8', 'replace') if isinstance(t, str) else t
_uu = lambda *tt: tuple(_u(t) for t in tt) 
# guarantee byte string in UTF8 encoding
_u8 = lambda t: t.encode('UTF-8', 'replace') if isinstance(t, unicode) else t
_uu8 = lambda *tt: tuple(_u8(t) for t in tt)

Beispiele:

text='Some string with codes > 127, like Zürich'
utext=u'Some string with codes > 127, like Zürich'
print "==> with _u, _uu"
print _u(text), type(_u(text))
print _u(utext), type(_u(utext))
print _uu(text, utext), type(_uu(text, utext))
print "==> with u8, uu8"
print _u8(text), type(_u8(text))
print _u8(utext), type(_u8(utext))
print _uu8(text, utext), type(_uu8(text, utext))
# with % formatting, always use _u() and _uu()
print "Some unknown input %s" % _u(text)
print "Multiple inputs %s, %s" % _uu(text, text)
# but with string.format be sure to always work with unicode strings
print u"Also works with formats: {}".format(_u(text))
print u"Also works with formats: {},{}".format(*_uu(text, text))
# ... or use _u8 and _uu8, because string.format expects byte strings
print "Also works with formats: {}".format(_u8(text))
print "Also works with formats: {},{}".format(*_uu8(text, text))

Hier finden Sie weitere Überlegungen dazu .




In einigen Fällen, wenn Sie Ihre Standardcodierung überprüfen ( print sys.getdefaultencoding() ), wird zurückgegeben, dass Sie ASCII verwenden. Wenn Sie zu UTF-8 wechseln, funktioniert es nicht, abhängig vom Inhalt Ihrer Variablen. Ich habe einen anderen Weg gefunden:

import sys
reload(sys)  
sys.setdefaultencoding('Cp1252')



Ich hatte das gleiche Problem, aber es funktionierte nicht für Python 3. Ich folgte diesem und es löste mein Problem:

enc = sys.getdefaultencoding()
file = open(menu, "r", encoding = enc)

Sie müssen die Codierung einstellen, wenn Sie die Datei lesen / schreiben.




Links