Python: Konvertierung von ISO-8859-1 / latin1 nach UTF-8

86

Ich habe diese Zeichenfolge, die mit dem E-Mail-Modul von Quoted-printable nach ISO-8859-1 dekodiert wurde. Dies gibt mir Zeichenfolgen wie "\ xC4pple", die "Äpple" (Apple auf Schwedisch) entsprechen würden. Ich kann diese Zeichenfolgen jedoch nicht in UTF-8 konvertieren.

>>> apple = "\xC4pple"
>>> apple
'\xc4pple'
>>> apple.encode("UTF-8")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 0: ordinal not in     range(128)

Was soll ich machen?

Zyberzero
quelle

Antworten:

119

Versuchen Sie zuerst, es zu dekodieren und dann zu kodieren:

apple.decode('iso-8859-1').encode('utf8')
Matte
quelle
5
Ich hatte einige Probleme beim Codieren von Inhalten in meine Sprache (Portugiesisch). Für mich funktionierte also string.decode ('iso-8859-1'). Codieren ('latin1'). Außerdem habe ich oben in meiner Python-Datei diese # - - Codierung: latin-1 - -
Moon13
148

Dies ist ein häufiges Problem, daher hier eine relativ gründliche Darstellung.

Für Nicht-Unicode-Zeichenfolgen (dh solche ohne uPräfix u'\xc4pple') muss von der nativen Codierung ( iso8859-1/ latin1, sofern nicht mit der rätselhaftensys.setdefaultencoding Funktion geändert ) zu dekodiert unicodeund dann in einen Zeichensatz codiert werden, der die gewünschten Zeichen anzeigen kann, in diesem Fall I. würde empfehlen UTF-8.

Hier ist zunächst eine praktische Dienstprogrammfunktion, mit deren Hilfe die Muster von Python 2.7-Zeichenfolgen und Unicode beleuchtet werden können:

>>> def tell_me_about(s): return (type(s), s)

Eine einfache Saite

>>> v = "\xC4pple" # iso-8859-1 aka latin1 encoded string

>>> tell_me_about(v)
(<type 'str'>, '\xc4pple')

>>> v
'\xc4pple'        # representation in memory

>>> print v
?pple             # map the iso-8859-1 in-memory to iso-8859-1 chars
                  # note that '\xc4' has no representation in iso-8859-1, 
                  # so is printed as "?".

Dekodieren einer iso8859-1-Zeichenfolge - Konvertieren einer einfachen Zeichenfolge in Unicode

>>> uv = v.decode("iso-8859-1")
>>> uv
u'\xc4pple'       # decoding iso-8859-1 becomes unicode, in memory

>>> tell_me_about(uv)
(<type 'unicode'>, u'\xc4pple')

>>> print v.decode("iso-8859-1")
Äpple             # convert unicode to the default character set
                  # (utf-8, based on sys.stdout.encoding)

>>> v.decode('iso-8859-1') == u'\xc4pple'
True              # one could have just used a unicode representation 
                  # from the start

Ein bisschen mehr Illustration - mit "Ä"

>>> u"Ä" == u"\xc4"
True              # the native unicode char and escaped versions are the same

>>> "Ä" == u"\xc4"  
False             # the native unicode char is '\xc3\x84' in latin1

>>> "Ä".decode('utf8') == u"\xc4"
True              # one can decode the string to get unicode

>>> "Ä" == "\xc4"
False             # the native character and the escaped string are
                  # of course not equal ('\xc3\x84' != '\xc4').

Codierung in UTF

>>> u8 = v.decode("iso-8859-1").encode("utf-8")
>>> u8
'\xc3\x84pple'    # convert iso-8859-1 to unicode to utf-8

>>> tell_me_about(u8)
(<type 'str'>, '\xc3\x84pple')

>>> u16 = v.decode('iso-8859-1').encode('utf-16')
>>> tell_me_about(u16)
(<type 'str'>, '\xff\xfe\xc4\x00p\x00p\x00l\x00e\x00')

>>> tell_me_about(u8.decode('utf8'))
(<type 'unicode'>, u'\xc4pple')

>>> tell_me_about(u16.decode('utf16'))
(<type 'unicode'>, u'\xc4pple')

Beziehung zwischen Unicode und UTF und Latin1

>>> print u8
Äpple             # printing utf-8 - because of the encoding we now know
                  # how to print the characters

>>> print u8.decode('utf-8') # printing unicode
Äpple

>>> print u16     # printing 'bytes' of u16
���pple

>>> print u16.decode('utf16')
Äpple             # printing unicode

>>> v == u8
False             # v is a iso8859-1 string; u8 is a utf-8 string

>>> v.decode('iso8859-1') == u8
False             # v.decode(...) returns unicode

>>> u8.decode('utf-8') == v.decode('latin1') == u16.decode('utf-16')
True              # all decode to the same unicode memory representation
                  # (latin1 is iso-8859-1)

Unicode-Ausnahmen

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

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

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

Man würde diese umgehen, indem man von der spezifischen Codierung (lateinisch-1, utf8, utf16) in Unicode konvertiert, z u8.decode('utf8').encode('latin1').

Vielleicht könnte man also die folgenden Prinzipien und Verallgemeinerungen zeichnen:

  • Ein Typ strist eine Gruppe von Bytes, die eine von mehreren Codierungen aufweisen können, z. B. Latin-1, UTF-8 und UTF-16
  • Ein Typ unicodeist eine Menge von Bytes, die in eine beliebige Anzahl von Codierungen konvertiert werden können, am häufigsten UTF-8 und Latin-1 (iso8859-1).
  • Der printBefehl verfügt über eine eigene Logik zum Codieren , die sys.stdout.encodingauf UTF-8 eingestellt ist und standardmäßig UTF-8 verwendet
  • Man muss a strin Unicode dekodieren , bevor man in eine andere Kodierung konvertiert.

All dies ändert sich natürlich in Python 3.x.

Hoffe das leuchtet.

Weiterführende Literatur

Und die sehr anschaulichen Beschimpfungen von Armin Ronacher:

Brian M. Hunt
quelle
12
Vielen Dank, dass Sie sich die Zeit genommen haben, eine so detaillierte Erklärung zu schreiben, eine der besten Antworten, die ich je auf stackoverflow gefunden habe :)
ruyadorno
5
Beeindruckend. Prägnant, sehr verständlich und mit gutem Beispiel erklärt. Vielen Dank, dass Sie die Intertubes verbessert haben.
Monkey Boson
22

Für Python 3:

bytes(apple,'iso-8859-1').decode('utf-8')

Ich habe dies für einen Text verwendet, der falsch als iso-8859-1 (mit Wörtern wie VeÅ \ x99ejnà © ) anstelle von utf-8 codiert ist . Dieser Code erzeugt die korrekte Version Veřejné .

Michal Skop
quelle
woher byteskommen aus?
Alvas
1
Dokumentation: Bytes . Siehe auch diese Frage und ihre Antworten.
Michal Skop
2
Für Dateien, die mit Anfragen mit fehlenden oder falschen Headern heruntergeladen wurden: r = requests.get(url)und dann direkt Einstellung r.encoding = 'utf-8'für mich funktioniert
Michal Skop
Dokumentation der bytes.decode- Methode.
Mike
10

In Unicode dekodieren, die Ergebnisse in UTF8 kodieren.

apple.decode('latin1').encode('utf8')
jd.
quelle
0
concept = concept.encode('ascii', 'ignore') 
concept = MySQLdb.escape_string(concept.decode('latin1').encode('utf8').rstrip())

Ich mache das, ich bin mir nicht sicher, ob das ein guter Ansatz ist, aber es funktioniert jedes Mal !!

Shashank Agarwal
quelle