如何从 stdin 读取输入并强制执行编码?
How to read inputs from stdin and enforce an encoding?
目标是连续读取 stdin
并在 Python2 和 Python3 中强制执行 utf8
。
我试过以下解决方案:
- Writing bytes to standard output in a way compatible with both, python2 and python3
- Python 3: How to specify stdin encoding
我试过:
#!/usr/bin/env python
from __future__ import print_function, unicode_literals
import io
import sys
# Supports Python2 read from stdin and Python3 read from stdin.buffer
#
user_input = getattr(sys.stdin, 'buffer', sys.stdin)
# Enforcing utf-8 in Python3
#
with io.TextIOWrapper(user_input, encoding='utf-8') as fin:
for line in fin:
# Reads the input line by line
# and do something, for e.g. just print line.
print(line)
代码在 Python3 中有效,但在 Python2 中,TextIOWrapper 没有读取函数,它会抛出:
Traceback (most recent call last):
File "testfin.py", line 12, in <module>
with io.TextIOWrapper(user_input, encoding='utf-8') as fin:
AttributeError: 'file' object has no attribute 'readable'
那是因为在 Python 中 user_input
,即 sys.stdin.buffer
是一个
_io.BufferedReader
对象及其属性具有 readable
:
<class '_io.BufferedReader'>
['__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', '_dealloc_warn', '_finalizing', 'close', 'closed', 'detach', 'fileno', 'flush', 'isatty', 'mode', 'name', 'peek', 'raw', 'read', 'read1', 'readable', 'readinto', 'readinto1', 'readline', 'readlines', 'seek', 'seekable', 'tell', 'truncate', 'writable', 'write', 'writelines']
而在 Python2 中 user_input
是一个文件对象,它的属性没有 readable
:
<type 'file'>
['__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'closed', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'mode', 'name', 'newlines', 'next', 'read', 'readinto', 'readline', 'readlines', 'seek', 'softspace', 'tell', 'truncate', 'write', 'writelines', 'xreadlines']
如果您不需要完整的io.TextIOWrapper
,而只需要一个用于阅读的解码流,您可以使用codecs.getreader()
创建一个解码包装器:
reader = codecs.getreader('utf8')(user_input)
for line in reader:
# do whatever you need...
print(line)
codecs.getreader('utf8')
为 codecs.StreamReader
创建一个工厂,然后使用原始流对其进行实例化。
我不确定 StreamReader
是否支持 with
上下文,但这可能不是绝对必要的(我想在阅读后不需要关闭 STDIN...)。
我已经在底层流只提供非常有限的接口的情况下成功地使用了这个解决方案。
更新(第二版)
从评论中可以清楚地看出,您实际上需要 io.TextIOWrapper
才能在交互模式下进行适当的行缓冲等; codecs.StreamReader
仅适用于管道输入等。
使用 this answer,我能够使交互式输入正常工作:
#!/usr/bin/env python
# coding: utf8
from __future__ import print_function, unicode_literals
import io
import sys
user_input = getattr(sys.stdin, 'buffer', sys.stdin)
with io.open(user_input.fileno(), encoding='utf8') as f:
for line in f:
# do whatever you need...
print(line)
这会创建一个 io.TextIOWrapper
并从二进制 STDIN 缓冲区强制编码。
您是否尝试过在 python 中强制使用 utf-8 编码,如下所示:
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
目标是连续读取 stdin
并在 Python2 和 Python3 中强制执行 utf8
。
我试过以下解决方案:
- Writing bytes to standard output in a way compatible with both, python2 and python3
- Python 3: How to specify stdin encoding
我试过:
#!/usr/bin/env python
from __future__ import print_function, unicode_literals
import io
import sys
# Supports Python2 read from stdin and Python3 read from stdin.buffer
#
user_input = getattr(sys.stdin, 'buffer', sys.stdin)
# Enforcing utf-8 in Python3
#
with io.TextIOWrapper(user_input, encoding='utf-8') as fin:
for line in fin:
# Reads the input line by line
# and do something, for e.g. just print line.
print(line)
代码在 Python3 中有效,但在 Python2 中,TextIOWrapper 没有读取函数,它会抛出:
Traceback (most recent call last):
File "testfin.py", line 12, in <module>
with io.TextIOWrapper(user_input, encoding='utf-8') as fin:
AttributeError: 'file' object has no attribute 'readable'
那是因为在 Python 中 user_input
,即 sys.stdin.buffer
是一个
_io.BufferedReader
对象及其属性具有 readable
:
<class '_io.BufferedReader'>
['__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', '_dealloc_warn', '_finalizing', 'close', 'closed', 'detach', 'fileno', 'flush', 'isatty', 'mode', 'name', 'peek', 'raw', 'read', 'read1', 'readable', 'readinto', 'readinto1', 'readline', 'readlines', 'seek', 'seekable', 'tell', 'truncate', 'writable', 'write', 'writelines']
而在 Python2 中 user_input
是一个文件对象,它的属性没有 readable
:
<type 'file'>
['__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'closed', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'mode', 'name', 'newlines', 'next', 'read', 'readinto', 'readline', 'readlines', 'seek', 'softspace', 'tell', 'truncate', 'write', 'writelines', 'xreadlines']
如果您不需要完整的io.TextIOWrapper
,而只需要一个用于阅读的解码流,您可以使用codecs.getreader()
创建一个解码包装器:
reader = codecs.getreader('utf8')(user_input)
for line in reader:
# do whatever you need...
print(line)
codecs.getreader('utf8')
为 codecs.StreamReader
创建一个工厂,然后使用原始流对其进行实例化。
我不确定 StreamReader
是否支持 with
上下文,但这可能不是绝对必要的(我想在阅读后不需要关闭 STDIN...)。
我已经在底层流只提供非常有限的接口的情况下成功地使用了这个解决方案。
更新(第二版)
从评论中可以清楚地看出,您实际上需要 io.TextIOWrapper
才能在交互模式下进行适当的行缓冲等; codecs.StreamReader
仅适用于管道输入等。
使用 this answer,我能够使交互式输入正常工作:
#!/usr/bin/env python
# coding: utf8
from __future__ import print_function, unicode_literals
import io
import sys
user_input = getattr(sys.stdin, 'buffer', sys.stdin)
with io.open(user_input.fileno(), encoding='utf8') as f:
for line in f:
# do whatever you need...
print(line)
这会创建一个 io.TextIOWrapper
并从二进制 STDIN 缓冲区强制编码。
您是否尝试过在 python 中强制使用 utf-8 编码,如下所示:
import sys
reload(sys)
sys.setdefaultencoding('utf-8')