我将外部程序的标准输出捕获到字节对象中:>>> from subprocess import *>>> stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]>>>
我将外部程序的标准输出捕获到一个 bytes
对象中:
>>> from subprocess import *
>>> stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
>>> stdout
b'total 0\n-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file1\n-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file2\n'
我想将其转换为普通的 Python 字符串,以便可以像这样打印它:
>>> print(stdout)
-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file1
-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file2
如何 bytes
使用 Python 3 str
对象转换为
See 在 Python 3 中将字符串转换为字节的最佳方法? for the other way around.
如果您不知道编码,那么要以 Python 3 和 Python 2 兼容的方式将二进制输入读入字符串,请使用古老的 MS-DOS CP437 编码:
PY3K = sys.version_info >= (3, 0)
lines = []
for line in stream:
if not PY3K:
lines.append(line)
else:
lines.append(line.decode('cp437'))
由于编码未知,因此需要将非英语符号转换为字符 cp437
(英语字符不会被转换,因为它们与大多数单字节编码和 UTF-8 匹配)。
将任意二进制输入解码为 UTF-8 是不安全的,因为您可能会得到以下结果:
>>> b'\x00\x01\xffsd'.decode('utf-8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 2: invalid
start byte
同样的情况也发生 latin-1
在 Python 2 中,它是流行的(默认的?)。请参阅 代码页布局 - 这是 Python 因臭名昭著的 ordinal not in range
.
更新 20150604 :有传言称 Python 3 具有 surrogateescape
将内容编码为二进制数据而不会导致数据丢失和崩溃的错误策略,但它需要转换测试 [binary] -> [str] -> [binary]
来验证性能和可靠性。
更新 20170116 :感谢 Nearoo 的评论 - 还可以使用 backslashreplace
错误处理程序对所有未知字节进行斜线转义。这仅适用于 Python 3,因此即使使用此解决方法,您仍会从不同的 Python 版本获得不一致的输出:
PY3K = sys.version_info >= (3, 0)
lines = []
for line in stream:
if not PY3K:
lines.append(line)
else:
lines.append(line.decode('utf-8', 'backslashreplace'))
请参阅 Python 的 Unicode 支持 。
更新 20170119 :我决定实现适用于 Python 2 和 Python 3 的斜线转义解码。它应该比 cp437
解决方案慢,但它应该 在每个 Python 版本上 相同的结果
# --- preparation
import codecs
def slashescape(err):
""" codecs error handler. err is UnicodeDecode instance. return
a tuple with a replacement for the unencodable part of the input
and a position where encoding should continue"""
#print err, dir(err), err.start, err.end, err.object[:err.start]
thebyte = err.object[err.start:err.end]
repl = u'\\x'+hex(ord(thebyte))[2:]
return (repl, err.end)
codecs.register_error('slashescape', slashescape)
# --- processing
stream = [b'\x80abc']
lines = []
for line in stream:
lines.append(line.decode('utf-8', 'slashescape'))