101 votes

Python : Conversion d'ISO-8859-1/latin1 en UTF-8

J'ai cette chaîne qui a été décodée de Quoted-printable à ISO-8859-1 avec le module de messagerie. Cela me donne des chaînes comme " \xC4pple "ce qui correspondrait à "Äpple" (pomme en suédois). Cependant, je ne peux pas convertir ces chaînes en UTF-8.

>>> 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)

Que dois-je faire ?

170voto

Brian M. Hunt Points 12506

Il s'agit d'un problème courant, aussi en voici une illustration relativement complète.

Pour les chaînes non unicode (c'est-à-dire celles qui n'ont pas de u préfixe comme u'\xc4pple' ), on doit décoder à partir de l'encodage natif ( iso8859-1 / latin1 à moins que modifié avec l'énigmatique sys.setdefaultencoding ) pour unicode puis encoder vers un jeu de caractères qui peut afficher les caractères que vous souhaitez, dans ce cas je recommanderais UTF-8 .

Tout d'abord, voici une fonction utilitaire pratique qui vous aidera à éclairer les modèles de chaîne et d'unicode de Python 2.7 :

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

Une chaîne de caractères simple

>>> 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 "?".

Décodage d'une chaîne iso8859-1 - convertir une chaîne simple en 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

Un peu plus d'illustration - avec "Ä"

>>> 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').

Encodage en 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')

Relation entre unicode et UTF et 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)

Exceptions Unicode

 >>> 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)

On peut contourner ces problèmes en convertissant l'encodage spécifique (latin-1, utf8, utf16) en unicode, par exemple. u8.decode('utf8').encode('latin1') .

On pourrait donc peut-être tirer les principes et généralisations suivants :

  • un type str est un ensemble d'octets, qui peut avoir l'un des nombreux codages suivants : Latin-1, UTF-8 et UTF-16.
  • un type unicode est un ensemble d'octets qui peuvent être convertis en un nombre quelconque de codages, le plus souvent UTF-8 et latin-1 (iso8859-1).
  • le site print Le commandement a sa propre logique d'encodage fixé à sys.stdout.encoding et par défaut UTF-8
  • On doit décoder un str en unicode avant de le convertir en un autre encodage.

Bien entendu, tout cela change dans Python 3.x.

J'espère que cela vous éclairera.

Autres lectures

Et les coups de gueule très illustratifs d'Armin Ronacher :

17 votes

Merci d'avoir pris le temps d'écrire une explication aussi détaillée, l'une des meilleures réponses que j'ai trouvées sur stackoverflow :)

6 votes

Wow. Succinct, très compréhensible, et expliqué par l'exemple. Merci de rendre les Intertubes meilleurs.

133voto

Mat Points 104488

Essayez d'abord de le décoder, puis de le coder :

apple.decode('iso-8859-1').encode('utf8')

6 votes

J'ai eu quelques problèmes pour encoder des choses dans ma langue (portugais), donc ce qui a fonctionné pour moi était string.decode('iso-8859-1').encode('latin1'). De plus, en haut de mon fichier python, j'ai ce # - -. - codage : latin-1 - -

3 votes

Euh, string.decode('iso-8859-1').encode('latin1') est exactement équivalent à juste string . ( 'latin-1' est un alias pour 'iso-8859-1' .)

25voto

Michal Skop Points 515

Pour Python 3 :

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

Je l'ai utilisé pour un texte incorrectement encodé en iso-8859-1 (montrant des mots comme VeÅ \x99ejn é ) au lieu de utf-8. Ce code produit une version correcte Veřejné .

0 votes

Où se trouve bytes proviennent-ils ?

1 votes

Documentation : octets . Voir aussi question et ses réponses.

3 votes

Pour les fichiers téléchargés avec des requêtes dont les en-têtes sont manquants ou incorrects : r = requests.get(url) et ensuite directement r.encoding = 'utf-8' a fonctionné pour moi

12voto

jd. Points 4600

Décoder en Unicode, encoder les résultats en UTF8.

apple.decode('latin1').encode('utf8')

0voto

Shashank Agarwal Points 332
concept = concept.encode('ascii', 'ignore') 
concept = MySQLdb.escape_string(concept.decode('latin1').encode('utf8').rstrip())

Je fais ça, je ne suis pas sûr que ce soit une bonne approche mais ça marche à chaque fois ! !!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X