web-dev-qa-db-fra.com

Comment imprimer du texte encodé en UTF-8 sur la console sous Python <3?

J'exécute un système Linux récent où tous mes paramètres régionaux sont UTF-8:

LANG=de_DE.UTF-8
LANGUAGE=
LC_CTYPE="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
...
LC_IDENTIFICATION="de_DE.UTF-8"
LC_ALL=

Maintenant, je veux écrire du contenu encodé en UTF-8 sur la console.

En ce moment Python utilise UTF-8 pour l’encodage FS mais s’en tient à ASCII pour l’encodage par défaut :

>>> import sys
>>> sys.getdefaultencoding()
'ascii'
>>> sys.getfilesystemencoding()
'UTF-8'

Je pensais que la meilleure façon (propre) de faire cela était de définir la variable d'environnement PYTHONIOENCODING. Mais il semble que Python l'ignore. Au moins sur mon système, je continue à obtenir ascii comme encodage par défaut, même après avoir défini le envvar.

# tried this in ~/.bashrc and ~/.profile (also sourced them)
# and on the commandline before running python
export PYTHONIOENCODING=UTF-8

Si je fais ce qui suit au début d'un script, cela fonctionne bien:

>>> import sys
>>> reload(sys)  # to enable `setdefaultencoding` again
<module 'sys' (built-in)>
>>> sys.setdefaultencoding("UTF-8")
>>> sys.getdefaultencoding()
'UTF-8'

Mais cette approche semble impure . Alors, quel est le bon moyen d'y parvenir?

Workaround

Au lieu de changer l'encodage par défaut - ce qui est pas une bonne idée (voir la réponse de Mesilliac) - je viens juste d'envelopper sys.stdout avec un StreamWriter comme ceci:

sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout)

Voir --- (this Gist pour une petite fonction utilitaire, qui la gère.

47
Brutus

Comment imprimer du texte encodé en UTF-8 sur la console sous Python <3?

print u"some unicode text \N{EURO SIGN}"
print b"some utf-8 encoded bytestring \xe2\x82\xac".decode('utf-8')

si vous avez une chaîne Unicode, imprimez-la directement. Si vous avez une chaîne d'octets, convertissez-la d'abord en Unicode.

Vos paramètres régionaux (LANG, LC_CTYPE) Indiquent des paramètres régionaux utf-8. Par conséquent, vous pouvez (en théorie) imprimer directement une chaîne bytest-utf-8 qui doit être affichée correctement dans votre terminal (si les paramètres du terminal sont cohérents avec les paramètres régionaux et ils devraient l'être), mais vous devez l'éviter: ne codez pas le codage de caractères de votre environnement dans votre script; affiche directement Unicode à la place.

Votre question comporte de nombreuses fausses hypothèses.

Vous n'avez pas besoin de définir PYTHONIOENCODING avec vos paramètres régionaux pour imprimer Unicode sur le terminal. Le paramètre régional utf-8 prend en charge tous les caractères Unicode, c’est-à-dire qu’il fonctionne tel quel.

Vous n'avez pas besoin de la solution de contournement sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout). Cela risque de se rompre si un code (que vous ne contrôlez pas) doit imprimer des octets et/ou s'il peut se rompre avec impression de la console Unicode sur Windows (page de code incorrecte, impossible d'imprimer des caractères indécodables) . Les paramètres régionaux corrects et/ou PYTHONIOENCODINGvvar sont suffisants. En outre, si vous devez remplacer sys.stdout, Alors tilisez io.TextIOWrapper() au lieu de codecs module comme package win-unicode-console fait.

sys.getdefaultencoding() n'est pas lié à vos paramètres régionaux ni à PYTHONIOENCODING. Votre hypothèse selon laquelle le réglage de PYTHONIOENCODING devrait changer sys.getdefaultencoding() est incorrecte. Vous devriez plutôt vérifier sys.stdout.encoding.

sys.getdefaultencoding() n'est pas utilisé lorsque vous imprimez sur la console. Il peut être utilisé comme solution de secours sur Python 2 si stdout est redirigé vers un fichier/canal à moins que PYTHOHIOENCODING ne soit défini:

$ python2 -c'import sys; print(sys.stdout.encoding)'
UTF-8
$ python2 -c'import sys; print(sys.stdout.encoding)' | cat
None
$ PYTHONIOENCODING=utf8 python2 -c'import sys; print(sys.stdout.encoding)' | cat
utf8

N'appelez pas sys.setdefaultencoding("UTF-8"); cela pourrait corrompre vos données silencieusement et/ou casser les modules tiers qui ne s'y attendaient pas. Rappelez-vous que sys.getdefaultencoding() est utilisé pour convertir des chaînes d'octets (str) en/de unicode in Python 2 implicitement Par exemple, "a" + u"b". Voir aussi, la citation dans la réponse de @ mesilliac .

8
jfs

Il semble que cela ne soit pas recommandé.

Fedora a suggéré en utilisant les paramètres régionaux du système comme valeur par défaut , mais apparemment, cela casse d'autres choses.

Voici une citation de la discussion sur la liste de diffusion :

 Les seuls encodages pris en charge par défaut dans Python sont: 
 
 Python 2.x: ASCII 
 Python 3.x: UTF-8 
 
 Si vous les modifiez, vous êtes seul et des choses étranges vont 
 Commencer. L’encodage par défaut n’affecte pas seulement 
 la traduction entre Python et le monde extérieur, mais également 
 toutes les conversions internes entre les chaînes de 8 bits et Unicode. . 
 
 Comme ce qui se passe dans le module pango (définir le codage par défaut de 
 Sur "utf-8" en rechargeant le module de site dans 
 Afin d'obtenir le Les API sys.setdefaultencoding () ne sont que 
 tout à fait fausses et entraîneront de graves problèmes puisque les objets Unicode 
 mettent en cache leur représentation codée par défaut. activez l'utilisation d'un codage par défaut basé sur les paramètres régionaux. 
 
 Si tout ce que vous voulez, c'est obtenir les codages de 
 stdout et stdin correctement configurés pour les canaux, vous devez 
 inst ead changez l'attribut .encoding de ceux-ci (seulement). 
 
 - 
 Marc-André Lemburg 
 eGenix.com 
28
mesilliac

Voici comment je le fais:

#!/usr/bin/python2.7 -S

import sys
sys.setdefaultencoding("utf-8")
import site

Noter la -S dans la ligne de démarcation. Cela indique à Python de ne pas importer automatiquement le module site. Le module site définit l’encodage par défaut et supprime la méthode afin qu’elle ne puisse pas être utilisée. à nouveau, mais honorera ce qui est déjà défini.

23
Keith

Si le programme n'affiche pas les caractères appropriés à l'écran, c'est-à-dire un symbole non valide, exécutez le programme à l'aide de la ligne de commande suivante:

PYTHONIOENCODING=utf8 python3 yourprogram.py

Ou, si votre programme est un module installé globalement:

PYTHONIOENCODING=utf8 yourprogram

Sur certaines plates-formes comme Cygwin (terminal mintty.exe) Avec Anaconda Python (ou Python 3), Exécutez simplement export PYTHONIOENCODING=utf8 Et exécutez ultérieurement le programme ne fonctionne pas, et vous devez toujours faire à chaque fois PYTHONIOENCODING=utf8 yourprogram pour exécuter le programme correctement.

Sous Linux, dans le cas de Sudo, vous pouvez essayer de passer l'argument -E Pour exporter les variables utilisateur vers le processus Sudo:

export PYTHONIOENCODING=utf8
Sudo -E python yourprogram.py

Si vous essayez ceci et que cela ne fonctionne pas, vous devrez entrer sur un shell Sudo:

Sudo /bin/bash
PYTHONIOENCODING=utf8 yourprogram

En relation:

  1. Comment imprimer du texte encodé UTF-8 sur la console sous Python <3?
  2. Changer l'encodage par défaut de Python?
  3. Forçage de UTF-8 sur cp1252 (Python3)
  4. Défini en permanence Python chemin pour Anaconda dans Cygwin
  5. https://superuser.com/questions/1374339/what-does-the-e-in-Sudo-e-do
  6. Pourquoi bash -c 'var = 5 printf "$ var"' n'imprime pas 5?
  7. https://unix.stackexchange.com/questions/296838/whats-the-difference-between-eval-and-exec
3
user