Gestion des Encodages de Chaînes de Caractères en Python

Avant d'aborder les spécificités de Python 2 et 3 concernant les encodages, il est essentiel de comprendre deux concepts fondamentaux : les littéraux de chaîne et les séquences d'octets (bytes).

Dans le code, nous définissons des variables pour représenter des données textuelles, par exemple s = "helloworld". Ces littéraux peuvent être utilisés pour des communications réseau ou stockés de manière persistante. Comme les données sont intrinsèquement représentées par des 0 et des 1 au niveau matériel, la conversion d'un littéral en un flux d'octets relève de l'encodage. C'est pourquoi il existe diveress méthodes d'encodage telles que utf-8, gbk, ascii, etc.

Python 2 et Python 3 distinguent ces deux concepts par des types distincts et des comportements par défaut différents :

Version Type Séquence d'Octets Type Littéral Chaîne Encodage par Défaut
Python 2 str unicode ascii
Python 3 bytes str utf-8

Nous nous concentrerons sur deux aspects principaux : la conversion entre séquences d'octets et littéraux de chaîne, ainsi que l'impact des encodages par défaut.

1. Conversion entre Séquences d'Octets et Littéraux de Chaîne

Les opérations de conversion sont les suivantes :

  • sequence_octets.decode(encodage) -> literal_chaine
  • literal_chaine.encode(encodage) -> sequence_octets

2. Impact de l'Encodage par Défaut

En Python 3, utf-8 est l'encodage par défaut. Les conversions s'effectuent principalement entre les littéraux de chaîne et utf-8, sans passer par une étape intermédiaire unicode au sens de Python 2 (utf-8 étant une variante de Unicode).

En Python 2, le processus est plus complexe, notamment dans la manière dont la console affiche les chaînes. Premièrement, comme les littéraux sont de type unicode, leur affichage peut ne pas correspondre à leur représentation textuelle directe, bien qu'ils représentent la même information sous-jacente.

# En Python 2
>>> chaine_fr = '你好'
>>> chaine_fr
u'\u4f60\u597d'

# Comparaison avec Python 3 (conceptuellement similaire)
# L'opération suivante produirait '你好' en Python 3
# >>> '\u4f60\u597d'.encode('utf-8').decode('utf-8')

Deuxièmement, en Python 2, les littéraux unicode doivent explicitement être précédés du préfixe u, par exemple chaine_unicode = u'你好'. Sans ce préfixe, la chaîne est traitée comme une séquence d'octets de type str.

Troisièmement, contrairement à Python 3 où l'on ne peut pas appliquer encode sur un type bytes, Python 2 permet d'appliquer encode sur une variable de type str. Lors de l'exécution de encode sur une séquence d'octets en Python 2, une étape implicite de decode est effectuée en utilisant l'encodage par défaut du système (ascii). Si la chaîne contient des caractères non-ASCII, cette opération échouera.

# Tentative d'encodage d'une chaîne avec des caractères non-ASCII en Python 2 échoue
>>> chaine_fr = '你好'
>>> chaine_fr.encode('gbk')
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)

# Encodage d'une chaîne purement ASCII sans problème
>>> chaine_ascii = 'hello'
>>> chaine_ascii.encode('gbk')
'hello'

Pour résoudre ce problème avec les chaînes contenant des caractères non-ASCII, il est nécessaire de modifier l'encodage par défaut de l'interpréteur :

# Modifier l'encodage par défaut de l'interpréteur
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

Étiquettes: Python 2 Python 3 encodage Unicode str

Publié le 21 juillet à 18h02