我将外部程序的标准输出捕获到一个字节对象中:

>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
>>>
>>> command_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(command_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

如何使用Python 3将字节对象转换为str?


当前回答

我想你真的想要这样:

>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
>>> command_text = command_stdout.decode(encoding='windows-1252')

Aaron的回答是正确的,只是你需要知道使用哪种编码。我相信Windows使用的是“Windows-1252”。只有当你的内容中有一些不寻常的(非ASCII)字符时,这才是重要的,但这会产生影响。

顺便说一句,这一点很重要,这是Python转而使用两种不同类型的二进制数据和文本数据的原因:它无法在它们之间进行神奇的转换,因为除非你告诉它,否则它不知道编码!您知道的唯一方法是阅读Windows文档(或在此处阅读)。

其他回答

由于这个问题实际上是关于子流程输出的,所以您可以使用更直接的方法。最现代的方法是使用subprocess.check_output并传递text=True(Python 3.7+),使用系统默认编码自动解码stdout:

text = subprocess.check_output(["ls", "-l"], text=True)

对于Python 3.6,Popen接受一个编码关键字:

>>> from subprocess import Popen, PIPE
>>> text = Popen(['ls', '-l'], stdout=PIPE, encoding='utf-8').communicate()[0]
>>> type(text)
str
>>> print(text)
total 0
-rw-r--r-- 1 wim badger 0 May 31 12:45 some_file.txt

如果您不处理子流程输出,标题中问题的一般答案是将字节解码为文本:

>>> b'abcde'.decode()
'abcde'

如果没有参数,将使用sys.getdefaultencoding()。如果数据不是sys.getdefaultencoding(),则必须在decode调用中显式指定编码:

>>> b'caf\xe9'.decode('cp1250')
'café'

尝试使用这个;此函数将忽略所有非字符集(如UTF-8)二进制文件,并返回一个干净的字符串。它针对Python 3.6及更高版本进行了测试。

def bin2str(text, encoding = 'utf-8'):
    """Converts a binary to Unicode string by removing all non Unicode char
    text: binary string to work on
    encoding: output encoding *utf-8"""

    return text.decode(encoding, 'ignore')

在这里,函数将获取二进制并对其进行解码(使用Python预定义的字符集将二进制数据转换为字符,忽略参数忽略二进制中的所有非字符集数据,并最终返回所需的字符串值)。

如果您不确定编码,请使用sys.getdefaultencoding()获取设备的默认编码。

我们可以使用bytes.decode(encoding='utf-8',errors='strict')对bytes对象进行解码以生成字符串。有关文档,请参阅bytes.decode。

Python 3示例:

byte_value = b"abcde"
print("Initial value = {}".format(byte_value))
print("Initial value type = {}".format(type(byte_value)))
string_value = byte_value.decode("utf-8")
# utf-8 is used here because it is a very common encoding, but you need to use the encoding your data is actually in.
print("------------")
print("Converted value = {}".format(string_value))
print("Converted value type = {}".format(type(string_value)))

输出:

Initial value = b'abcde'
Initial value type = <class 'bytes'>
------------
Converted value = abcde
Converted value type = <class 'str'>

注意:在Python 3中,默认情况下编码类型为UTF-8。因此,<byte_string>.decode(“utf-8”)也可以写成<byte-string>.decode()

虽然@Aaron Maenpaa的回答很有效,但一位用户最近问道:

还有什么更简单的方法吗?”fhand.read().decode(“ASCII”)'[…]太长了!

您可以使用:

command_stdout.decode()

decode()有一个标准参数:

codec.decode(obj,编码='utf-8',错误='strict')

从系统-系统特定参数和功能:

要从标准流中写入或读取二进制数据,请使用底层二进制缓冲区。例如,要将字节写入stdout,请使用sys.stdout.buffer.write(b'abc')。