2013-05-14 10 views
19

Beim Portieren von Code aus Python 2 nach Python 3, stoße ich auf dieses Problem beim Lesen von UTF-8-Text von der Standardeingabe. In Python 2, das funktioniert gut:Python 3: Wie stdin codieren

for line in sys.stdin: 
    ... 

Aber Python 3 erwartet ASCII von sys.stdin, und wenn es nicht-ASCII-Zeichen in der Eingabe ist, erhalte ich die Fehlermeldung:

UnicodeDecodeError: 'ascii' codec can't decode byte .. in position ..: ordinal not in range(128)

für eine normale Datei, würde ich die Codierung angeben, wenn Sie die Datei öffnen:

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

Aber wie kann ich die Codierung für Standardeingabe angeben? Andere haben SO Beiträge vorgeschlagen

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

jedoch verwenden, das funktioniert nicht in Python 3. Ich immer noch die gleiche Fehlermeldung. Ich benutze Ubuntu 12.04.2 und mein Gebietsschema ist auf en_US.UTF-8 eingestellt.

Antwort

35

Python 3 tut nicht erwartet ASCII von sys.stdin. Es wird stdin im Textmodus öffnen und eine fundierte Schätzung, welche Codierung verwendet wird. Diese Vermutung kann auf ASCII herunterkommen, aber das ist nicht selbstverständlich. In der sys.stdin documentation, wie der Codec ausgewählt ist.

Wie andere Dateiobjekte, die im Textmodus geöffnet werden, wird das Objekt sys.stdin von io.TextIOBase base class abgeleitet; Es hat ein .buffer Attribut, das auf die zugrunde liegende gepufferte IO-Instanz zeigt (die wiederum ein .raw Attribut hat).

Wrap die sys.stdin.buffer Attribut in einem neuen io.TextIOWrapper() instance eine andere Codierung zu spezifizieren:

import io 
import sys 

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

Alternativ setzen die PYTHONIOENCODING environment variable auf den gewünschten Codec wenn Python läuft.

+0

Danke, das hat den Trick gemacht! –

+2

Was ist die nächste Entsprechung für Python2.6? – bukzor

+1

@bukzor: Nächste Option: Öffnen Sie den Dateideskriptor direkt mit 'io.open()'; '0' ist' stdin': 'io.open (0)' gibt ein 'TextIOWrapper()' -Objekt zurück. –