Il existe des différences importantes entre python 2 et 3 en terme d'encoding.
Sur python 2 l'encoding est en ASCII alors que son successeur encode en unicode (dans les exemples ci dessous nous utiliserons une implementation de Unicode : UTF-8).
La table ASCII ne couvre pas tous les caractères des langues connues, c'est pour cela que l'Unicode est devenu la référence notamment dans python 3.
Si vous souhaitez lancer les scripts suivants et que le résultat n'est pas identique, pensez à vérifier l'encodage de votre IDE. Par exemple dans VSCode il faut mettre
Copier le code
1 2 3 4 { "files.encoding": "utf8", ... }
L'IDE s'appuie sur l'OS qui l'héberge donc vous pouvez aussi modifier la langue de l'OS qui aura un impact sur l'encodage.
En python 2 lorsque l'on déclare une chaine de caractère c'est un str, il faut le convertir en unicode pour éviter les erreurs avec decode('utf-8'). Ainsi maintenant vous allez travailler sur un objet unicode.
On peut faire l'opération inverse avec .encode('utf-8') pour obtenir le str qui est simplement une séquence de bytes.
Copier le code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 >>> import sys >>> print(sys.version_info) sys.version_info(major=2, minor=7, micro=14, releaselevel='final', serial=0) >>> a = '的' >>> a '\xe7\x9a\x84' >>> str = '的' >>> print str 的 >>> str_d = str.decode('utf-8') >>> print(str_d) u'\u7684' >>> str_e = str_d.encode('utf-8') >>> print str_e 的
En python 3 la différence importante porte sur str qui utilise les valeurs unicode et non une séquence de bytes. Et un nouveau type bytes fut introduit dans cette version majeure qui est défini par une séquence d'octets.
Copier le code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 >> import sys >> print(sys.version_info) >> sys.version_info(major=3, minor=7, micro=0, releaselevel='final', serial=0) >> print('的') 的 # On remarque cette fois on est pas sur une sequence de bytes mais sur de l'unicode comme le caratère est rendu >> print(type('的')) <class 'str'> # Toujours un str mais cette fois python 3 nous retourne de l'unicode ... # ...il faut commencer par un encode() afin de le convertir en sequence de bytes (type bytes) >> ch = '的'.encode('utf8') >> print(ch) b'\xe7\x9a\x84' >> print(type(ch)) <class 'bytes'> # On fait l'opération inverse pour obtenir le caratère unicode >> print(ch.decode('utf-8')) 的 >> print(type(ch.decode('utf-8'))) <class 'str'> # On peut aussi directement écrire un bytes avec b comme préfix à la chaine >> b = b'\xe7\x9a\x84' >> print(b) b'\xe7\x9a\x84' >> print(type(b)) <class 'bytes'> # et le convertir en unicode comme auparavant avec decode('utf-8') >> print(b.decode('utf-8')) 的 >> print(type(b.decode('utf-8'))) <class 'str'>
En résumé sur python
- bytes.decode() => convertion d'un bytes vers unicode
- str.encode() => convertion d'une chaine unicode vers une séquence de bytes
Cependant en fonction de la version de python il faut soit utiliser encode soit decode pour le convertir dans le bon encodage.
Souvent en python 2 il fallait mettre cette ligne lorsque l'on manipulait les string # coding utf8
Si on met un mauvais encodage
Copier le code
1 2 3 4 5 6 7 8 9 # coding: iso-8859-1 print('的') >> ç Result with wrong encoding # coding: utf-8 print('的') >> 的 Result with good encoding
On peut décider de changer l'encodage avec la librairie sys
Copier le code
1 2 3 4 5 6 7 8 9 10 11 print(sys.stdout.encoding) print('的') sys.stdout.reconfigure(encoding='iso-8859-1') print('的') >> utf-8 >> 的 >> Traceback (most recent call last): File ".\update-encoding-in-file.py", line 4, in <module> print('的') UnicodeEncodeError: 'latin-1' codec can't encode character '\u7684' in position 0: ordinal not in range(256)
Si on veut encoder dans un format spécifique les données à destination d'un fichier on va modifier la variable d'environnement PYTHONIOENCODING=UTF-8
Copier le code
1 2 3 4 5 6 7 >> cat enc.py print('Héllo') >> python .\enc.py > out.txt HÚllo >> set PYTHONIOENCODING=utf8 >> python .\enc.py > out.txt Héllo
Voilà l'encodage n'a plus de secret pour vous !