C'est un problème courant, voici donc une illustration relativement complète.
Pour les chaînes non-unicode (c'est-à-dire celles sans u
préfixe comme u'\xc4pple'
), il faut décoder à partir du codage natif ( iso8859-1
/ latin1
, sauf si modifié avec lasys.setdefaultencoding
fonction énigmatique ) vers unicode
, puis encoder dans un jeu de caractères qui peut afficher les caractères que vous souhaitez, dans ce cas je Je recommande UTF-8
.
Tout d'abord, voici une fonction utilitaire pratique qui vous aidera à éclairer les modèles de chaîne Python 2.7 et d'Unicode:
>>> def tell_me_about(s): return (type(s), s)
Une corde simple
>>> v = "\xC4pple"
>>> tell_me_about(v)
(<type 'str'>, '\xc4pple')
>>> v
'\xc4pple'
>>> print v
?pple
Décoder une chaîne iso8859-1 - convertir une chaîne simple en unicode
>>> uv = v.decode("iso-8859-1")
>>> uv
u'\xc4pple'
>>> tell_me_about(uv)
(<type 'unicode'>, u'\xc4pple')
>>> print v.decode("iso-8859-1")
Äpple
>>> v.decode('iso-8859-1') == u'\xc4pple'
True
Un peu plus d'illustration - avec «Ä»
>>> u"Ä" == u"\xc4"
True
>>> "Ä" == u"\xc4"
False
>>> "Ä".decode('utf8') == u"\xc4"
True
>>> "Ä" == "\xc4"
False
Encodage en UTF
>>> u8 = v.decode("iso-8859-1").encode("utf-8")
>>> u8
'\xc3\x84pple'
>>> 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
>>> print u8.decode('utf-8')
Äpple
>>> print u16
���pple
>>> print u16.decode('utf16')
Äpple
>>> v == u8
False
>>> v.decode('iso8859-1') == u8
False
>>> u8.decode('utf-8') == v.decode('latin1') == u16.decode('utf-16')
True
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 pourrait les contourner en convertissant l'encodage spécifique (latin-1, utf8, utf16) en unicode par exemple u8.decode('utf8').encode('latin1')
.
Alors peut-être pourrait-on tirer les principes et généralisations suivants:
- un type
str
est un ensemble d'octets, qui peut avoir l'un des nombreux codages tels que Latin-1, UTF-8 et UTF-16
- un type
unicode
est un ensemble d'octets qui peuvent être convertis en n'importe quel nombre d'encodages, le plus souvent UTF-8 et latin-1 (iso8859-1)
- la
print
commande a sa propre logique d'encodage , définie sur sys.stdout.encoding
et par défaut sur UTF-8
- Il faut décoder un
str
en unicode avant de le convertir en un autre encodage.
Bien sûr, tout cela change dans Python 3.x.
J'espère que c'est éclairant.
Lectures complémentaires
Et les diatribes très illustratives d'Armin Ronacher: