web-dev-qa-db-fra.com

Python 3: comment spécifier l'encodage stdin

Lors du portage de code de Python 2 à Python 3, je rencontre ce problème lors de la lecture de texte UTF-8 à partir de l'entrée standard. Dans Python 2, cela fonctionne très bien:

for line in sys.stdin:
    ...

Mais Python 3 attend ASCII de sys.stdin , et s'il y en a) caractères non ASCII en entrée, j'obtiens l'erreur:

UnicodeDecodeError: le codec 'ascii' ne peut pas décoder l'octet .. en position ..: l'ordinal n'est pas dans la plage (128)

Pour un fichier normal, je préciserais l'encodage lors de l'ouverture du fichier:

with open('filename', 'r', encoding='utf-8') as file:
    for line in file:
        ...

Mais comment puis-je spécifier l'encodage pour l'entrée standard? D'autres SO posts (par exemple Comment changer l'encodage stdin sur python ) ont suggéré d'utiliser

input_stream = codecs.getreader('utf-8')(sys.stdin)
for line in input_stream:
    ...

Cependant, cela ne fonctionne pas dans Python 3. Je reçois toujours le même message d'erreur. J'utilise Ubuntu 12.04.2 et mes paramètres régionaux sont définis sur en_US.UTF-8.

34
Seppo Enarvi

Python 3 n'attend pas ASCII de sys.stdin. Il ouvrira stdin en mode texte et faites une supposition éclairée sur le codage utilisé. Cette supposition peut se résumer à ASCII, mais ce n'est pas une donnée. Voir la documentation sys.stdin sur la façon dont le codec est sélectionné.

Comme les autres objets fichier ouverts en mode texte, l'objet sys.stdin Dérive de la classe de base io.TextIOBase ; il a un attribut .buffer pointant vers la mémoire tampon sous-jacente IO instance (qui à son tour a un attribut .raw).

Enveloppez l'attribut sys.stdin.buffer Dans une nouvelle io.TextIOWrapper() instance pour spécifier un encodage différent:

import io
import sys

input_stream = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')

Sinon, définissez la variable d'environnement PYTHONIOENCODING sur le codec souhaité lors de l'exécution de python.

À partir de Python 3.7 et ultérieur, vous pouvez également reconfigurer les wrappers std* Existants , à condition de le faire au début (avant la lecture des données) :

# Python 3.7 and newer
sys.stdin.reconfigure(encoding='utf-8')
67
Martijn Pieters