C'est beaucoup plus facile que Python 2, mais dans certains environnements, vous pouvez rencontrer des erreurs UnicodeErrors inattendues dans Python 3. Voyons la gestion de divers encodages Python à partir de Python 3.6.
filesystem encoding (sys.getfilesystemencoding()
)
Ce codage est principalement utilisé pour les chemins de fichiers, mais il est également utilisé pour les arguments de ligne de commande. (Sinon, vous aurez du mal à passer le chemin du fichier comme argument de ligne de commande)
De plus, comme les paramètres régionaux sont liés, ils sont en fait utilisés lorsque vous travaillez avec la glibc, etc. C'est peut-être un vestige de l'ère Python 2, mais maintenant je pense que l'appeler codage système plutôt que codage système de fichiers représente la réalité.
preferred encoding (locale.getpreferredencoding()
)
Cet encodage est principalement utilisé pour le contenu des fichiers texte. ʻUtilisé lors de l'ouverture d'un fichier texte avec la fonction open`.
Le codage d'entrée / sortie standard est le codage du système de fichiers pour les terminaux et le codage préféré pour les autres, mais il peut être modifié avec la variable d'environnement PYTHONIOENCODING
.
default encoding (sys.getdefaultencoding()
)
Il s'agit du codage par défaut utilisé lorsque vous ne spécifiez pas explicitement un codage lors de la conversion entre une chaîne unicode ( str '') et une chaîne d'octets (
octets ''). En Python 3, il est complètement UTF-8 fixe quel que soit l'environnement.
>>> "Bonjour".encode()
b'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf'
>>> _.decode()
'Bonjour'
C'était ascii à l'ère Python 2, et il y avait une conversion de type implicite, donc cela avait tendance à être une source de problèmes. (Il y avait aussi un hack pour forcer utf-8 à exécuter une application qui ne pensait pas au multi-octet)
Python 3 ne fait pas de conversion de type implicite entre str et bytes, c'est donc juste un argument par défaut. Vous pouvez oublier l'existence elle-même.
macOS, android
Comme il est fixé à UTF-8 au niveau du système d'exploitation, le codage du système de fichiers sera toujours UTF-8.
L'encodage préféré est toujours UTF-8 fixé pour Android et peut être modifié avec les paramètres régionaux pour macOS, mais je pense que c'est rarement un problème. (Si la locale est définie, ce sera la même chose que Linux décrit plus tard)
Windows
Étant donné que Windows utilise des API basées sur W à la fois lors de l'ouverture de fichiers et lors de la réception d'arguments de ligne de commande, le codage du système de fichiers est rarement utilisé.
Le comportement lors du traitement des chemins de fichiers sous forme de chaînes d'octets était la page de code actuelle cp932 '' car jusqu'à Python 3.5, il s'agissait d'un appel Windows A API. À partir de Python 3.6, ce comportement a changé et la conversion UTF-8 => UTF-16 et les API basées sur W sont utilisées, le codage du système de fichiers est donc
utf-8 ''. (Il existe également des variables d'environnement pour revenir au comportement de Python 3.5)
Le codage préféré, en revanche, utilise toujours des pages de codes. C'est un héritage jusqu'à ce que Microsoft fasse le codage de fichier texte standard UTF-8. Je suis désolé.
Le plus décevant est l'autre Unix. Cela dépend des paramètres régionaux (`` LC_CTYPE ''). Si quelqu'un dit encore LANG = ja_JP.eucJP
, le codage du système de fichiers et le codage préféré seront EUC-JP. Si vous voulez créer un fichier texte en UTF-8, même si vous ne voulez pas du tout prendre en charge Windows, spécifiez le codage explicitement dans la fonction ʻopen` pour les environnements où la locale n'est pas UTF-8.
La dépendance locale est particulièrement décevante car le codage par défaut (C ou POSIX) (LC_CTYPE) pour les paramètres régionaux est par défaut ASCII.
Certaines personnes utilisent les paramètres régionaux C ou POSIX car ils n'aiment pas le comportement de diverses commandes telles que le tri selon les paramètres régionaux. Les images intégrées ou conteneurs peuvent ne pas avoir les paramètres régionaux en_US.utf8 ou ja_JP.utf8 pour réduire le poids. De plus, si vous ssh depuis mac (parce que la variable d'environnement LANG est envoyée), vous pouvez obtenir une erreur et revenir à C lorsque vous essayez d'utiliser ja_JP.UTF-8 sur Linux qui n'a que en_US.UTF-8. A cette époque, Python est complètement en mode ASCII.
$ export LC_ALL=C
$ echo 'print("Bonjour\n")' > hello
$ ruby hello
Bonjour
$ perl hello
Bonjour
$ python3 hello
Traceback (most recent call last):
File "hello", line 1, in <module>
print("\u3053\u3093\u306b\u3061\u306f\n")
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-4: ordinal not in range(128)
Si le codage du système de fichiers peut rester ASCII, vous pouvez spécifier le codage d'entrée / sortie standard avec PYTHONIOENCODING sans définir de paramètres régionaux. Écrivez-le dans .bashrc ou crontab.
$ PYTHONIOENCODING=utf-8 python3 hello
Bonjour
La première chose à retenir est la commande locale
, qui affiche la locale actuelle, et la commande locale -a
, qui affiche une liste des locales disponibles.
$ locale
LANG=C.UTF-8
LANGUAGE=en_US:en
LC_CTYPE="C.UTF-8"
LC_NUMERIC="C.UTF-8"
LC_TIME="C.UTF-8"
LC_COLLATE="C.UTF-8"
LC_MONETARY="C.UTF-8"
LC_MESSAGES="C.UTF-8"
LC_PAPER="C.UTF-8"
LC_NAME="C.UTF-8"
LC_ADDRESS="C.UTF-8"
LC_TELEPHONE="C.UTF-8"
LC_MEASUREMENT="C.UTF-8"
LC_IDENTIFICATION="C.UTF-8"
LC_ALL=
$ locale -a
C
C.UTF-8
POSIX
en_US.utf8
Je pense que C.UTF-8
est inclus dans Linux moderne. Une version UTF-8 de la locale C qui ne fait rien de plus.
Il est parfait pour les personnes qui souhaitent utiliser les paramètres régionaux C, mais qui souhaitent utiliser des noms de fichiers UTF-8. S'il n'existe pas, vous devriez pouvoir le créer avec sudo localedef -c -i POSIX -f UTF-8 C.UTF-8
si vous avez les privilèges root.
Si ja_JP.UTF-8 ou en_US.UTF-8 existe et que vous souhaitez l'utiliser, définissez-le dans la variable d'environnement LANG et vérifiez-le avec la commande locale.
$ export LANG=en_US.utf8
$ locale
LANG=en_US.utf8
LANGUAGE=en_US:en
LC_CTYPE="en_US.utf8"
LC_NUMERIC="en_US.utf8"
LC_TIME="en_US.utf8"
LC_COLLATE="en_US.utf8"
LC_MONETARY="en_US.utf8"
LC_MESSAGES="en_US.utf8"
LC_PAPER="en_US.utf8"
LC_NAME="en_US.utf8"
LC_ADDRESS="en_US.utf8"
LC_TELEPHONE="en_US.utf8"
LC_MEASUREMENT="en_US.utf8"
LC_IDENTIFICATION="en_US.utf8"
LC_ALL=
Je veux utiliser la locale C! Mais je veux utiliser UTF-8! Mais je ne peux pas faire C.UTF-8! Dans ce cas, contrôlons-le un peu plus précisément.
De chaque LC_XXXXX, celui que Python utilise pour déterminer le codage est LC_CTYPE
.
La variable d'environnement LANG
définit le LC_XXXX entier sauf LC_ALL
et peut être remplacée individuellement pour chaque LC_XXXX, mais si LC_ALL
est défini, elle écrasera tout davantage.
Vous pouvez donc définir LC_CTYPE sur certains paramètres régionaux UTF-8 tout en définissant LANG = C.
$ export LANG=C
$ export LC_CTYPE=en_US.UTF-8
$ locale
LANG=C
LANGUAGE=en_US:en
LC_CTYPE=en_US.UTF-8
LC_NUMERIC="C"
LC_TIME="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_PAPER="C"
LC_NAME="C"
LC_ADDRESS="C"
LC_TELEPHONE="C"
LC_MEASUREMENT="C"
LC_IDENTIFICATION="C"
LC_ALL=
$ locale charmap
UTF-8
$ python3 -c 'import sys; print(sys.getfilesystemencoding())'
utf-8
Recommended Posts