将字节转换为字符串在Python 3中。

3717

我将外部程序的标准输出捕获到一个 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

如何将Python 3中的bytes对象转换为str

查看在Python 3中将字符串转换为字节的最佳方法以了解另一种方式。


156
为什么 str(text_bytes) 不起作用?这对我来说似乎很奇怪。 - Charlie Parker
71
因为str(text_bytes)无法指定编码方式。根据text_bytes中包含的内容,使用text_bytes.decode('cp1250')可能会得到与text_bytes.decode('utf-8')截然不同的字符串。 - Craig Anderson
17
现在的 str 函数不再自动将其它类型转换为字符串。由于某些原因,必须显式指定编码方式。只需要将编码方式设置为 utf-8 并检查你的代码是否正常工作即可。例如:var = var.decode('utf-8') - Charlie Parker
16
在Python 3中,unicode_text = str(bytestring, character_encoding) 可以正常工作。虽然 unicode_text = bytestring.decode(character_encoding) 更可取,以避免与仅为 bytes_obj 生成文本表示的 str(bytes_obj) 混淆,而不是将其解码为文本: str(b'\xb6', 'cp1252') == b'\xb6'.decode('cp1252') == '¶',并且 str(b'\xb6') == "b'\\xb6'" == repr(b'\xb6') != '¶' - jfs
3
此外,您可以将 text=True 传递给 subprocess.run().Popen(),然后您将获得一个字符串,无需转换字节。或者在任一函数中指定 encoding="utf-8" - David Gilbertson
@CharlieParker - 我从未遇到过使用str(<bytes>)时得到的字符串的用例,但也许只是为了与其他str调用保持一致。我本以为它们可以默认为UTF-8编码,但也许是因为Windows有太多奇怪的编码方式,所以它不会默认为UTF-8;但我同意你的观点。 - NeilG
24个回答

22

如果你遇到了这个错误:

utf-8编解码器无法解码字节0x8a,

那么最好使用以下代码将字节转换为字符串:

bytes = b"abcdefg"
string = bytes.decode("utf-8", "ignore") 

21

如果您在尝试使用decode()时遇到以下错误:

  

AttributeError:'str'对象没有属性'decode'

您还可以在转换中直接指定编码类型:

>>> my_byte_str
b'Hello World'

>>> str(my_byte_str, 'utf-8')
'Hello World'

21

字节

m=b'This is bytes'

转换成字符串

方法1

m.decode("utf-8")
或者
m.decode()

方法2

import codecs
codecs.decode(m,encoding="utf-8")
或者
import codecs
codecs.decode(m)

方法三

str(m,encoding="utf-8")
或者
str(m)[2:-1]

结果

'This is bytes'

17
我们可以使用 bytes.decode(encoding='utf-8', errors='strict') 将字节对象解码为字符串。 有关文档,请参见 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()

9

对于Python 3,这是一种更安全和更符合Python风格的方法,可以将byte转换为string

def byte_to_str(bytes_or_str):
    if isinstance(bytes_or_str, bytes): # Check if it's in bytes
        print(bytes_or_str.decode('utf-8'))
    else:
        print("Object not of byte type")

byte_to_str(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')

输出:

total 0
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file1
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file2

8

当使用来自Windows系统的数据(带有\r\n换行符)时,我的回答是:

String = Bytes.decode("utf-8").replace("\r\n", "\n")

为什么?尝试使用多行输入文件Input.txt:

Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8")
open("Output.txt", "w").write(String)

你的所有行尾都会被加倍(变为\r\r\n),导致额外的空行。Python的文本读取函数通常会将行尾标准化,使字符串只使用\n。如果你从Windows系统接收到二进制数据,则Python无法进行标准化处理。因此,
Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8").replace("\r\n", "\n")
open("Output.txt", "w").write(String)

将会复制您的原始文件。


5

对于您的“运行shell命令并将其输出作为文本而不是字节”的具体情况,在Python 3.7上,您应该使用subprocess.run并传递text=True(以及capture_output=True以捕获输出)。

command_result = subprocess.run(["ls", "-l"], capture_output=True, text=True)
command_result.stdout  # is a `str` containing your program's stdout

text曾经被称为universal_newlines,并在Python 3.7中更改(或者说别名)。如果您想支持Python 3.7之前的版本,请传入universal_newlines=True而不是text=True


4

来自sys — 系统特定参数和函数

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


4
子进程的管道已经是二进制缓冲区。你的回答没有解决如何从生成的“bytes”值中获取字符串值的问题。 - Martijn Pieters

4

试试这个:

bytes.fromhex('c3a9').decode('utf-8') 

2
def toString(string):    
    try:
        return v.decode("utf-8")
    except ValueError:
        return string

b = b'97.080.500'
s = '97.080.500'
print(toString(b))
print(toString(s))

1
虽然这段代码可能回答了问题,但提供关于它是如何解决问题以及为什么解决问题的附加上下文可以改善答案的长期价值。请记住,你正在为未来的读者回答问题,而不仅仅是现在提问的人!请编辑你的回答以添加解释,并指出哪些限制和假设适用。此外,提到为什么这个答案比其他答案更合适也不会有任何损失。 - Dev-iL
嗨@Dev-iL,如果您是管理员,您能否告诉我管理员是否可以删除像这样毫无意义、空洞、不连贯的答案:https://stackoverflow.com/a/68310461/134044 ? - NeilG
1
@NeilG 我不是版主(请注意,我的昵称旁边没有钻石标志)。如果您认为某篇帖子质量低劣,您应该举报它,如果社区与您意见一致,它将被删除。 - Dev-iL

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接