Python 3: Как указать stdin-кодирование
При переносе кода с Python 2 на Python 3 я сталкиваюсь с этой проблемой при чтении текста UTF-8 со стандартного ввода. В Python 2 это прекрасно работает:
for line in sys.stdin:
...
Но Python 3 ожидает ASCII от sys.stdin, и если на входе есть символы, отличные от ASCII, я получаю ошибку:
UnicodeDecodeError: кодек ascii не может декодировать байт.. в позиции..: порядковый номер не в диапазоне (128)
Для обычного файла я должен указать кодировку при открытии файла:
with open('filename', 'r', encoding='utf-8') as file:
for line in file:
...
Но как я могу указать кодировку для стандартного ввода? Другие сообщения SO предложили использовать
input_stream = codecs.getreader('utf-8')(sys.stdin)
for line in input_stream:
...
Однако это не работает в Python 3. Я все равно получаю то же сообщение об ошибке. Я использую Ubuntu 12.04.2, и мой язык установлен в en_US.UTF-8.
Ответы
Ответ 1
Python 3 не ожидает ASCII от sys.stdin
. Он откроет stdin
в текстовом режиме и сделает обоснованное предположение о том, какая кодировка используется. Эта догадка может доходить до ASCII
, но это не так. См. sys.stdin
документация о том, как выбран кодек.
Как и другие файловые объекты, открытые в текстовом режиме, объект sys.stdin
происходит из базового класса io.TextIOBase
; он имеет атрибут .buffer
, указывающий на базовый буферный экземпляр IO (который, в свою очередь, имеет атрибут .raw
).
Оберните атрибут sys.stdin.buffer
в новый io.TextIOWrapper()
экземпляр, чтобы указать другую кодировку:
import io
import sys
input_stream = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')
В качестве альтернативы установите PYTHONIOENCODING
переменную окружения в нужный кодек при запуске python.