3775

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

>>>从子流程导入*>>>stdout=Popen(['ls','-l'],stdout=管道).communicate()[0]>>>标准输出b'总计0\n-rw-rw-r--1托马斯托马斯0 3月3日07:03 file1\n-rw-rw-r--1托马斯托马斯0 3日07:00 file2\n'

我想把它转换成一个普通的Python字符串,这样我就可以这样打印它:

>>>打印(标准输出)-rw-rw-r--1托马斯托马斯3月0日07:03文件1-rw-rw-r--1托马斯托马斯3月0日07:03文件2

如何转换字节对象到字符串使用Python 3?


请参见在Python 3中将字符串转换为字节的最佳方法?换一种方式。

7
  • 164
    为什么不str(文本字节)工作?这在我看来很奇怪。 评论 2019年3月14日22:25
  • 75
    @Charlie Parker因为str(文本字节)无法指定编码。根据text_bytes中的内容,文本字节解码('cp1250)`可能会导致与text_bytes.解码('utf-8'). 评论 2019年3月31日17:32
  • 18
    所以字符串函数不再转换为实际字符串。出于某种原因,人们必须明确地说出编码,我懒得通读原因。只需将其转换为utf-8型看看你的代码是否有效。例如var=var.decode('utf-8') 评论 2019年4月22日23:32
  • 18
    @克雷格安德森:unicode_text=str(字节串,character_encoding)在Python 3上正常工作。虽然unicode文本=字节字符串解码(字符编码)更可取的是避免与just混淆str(字节_obj)为生成文本表示的字节_obj而不是将其解码为文本:str(b'\xb6','cp1252')==b'\xb6'.decode('cp1252])=='¶'str(b'\xb6')==“b'\\xb6`”==repr(b'\ xb6'')!='¶'
    – jfs公司
    评论 2020年4月12日5:11
  • 此外,你可以通过text=真subprocess.run().Popen()然后您将得到一个字符串,无需转换字节。或指定编码=“utf-8”至任一功能。 评论 2022年9月13日5:46

23答案23

重置为默认值
5722

解码字节对象要生成字符串:

>>>b“abcde”解码(“utf-8”)“abcode”

上述示例假设那个字节对象是UTF-8格式的,因为它是一种通用编码。然而,您应该使用数据实际使用的编码!

5
  • 1
    是的,但考虑到这是windows命令的输出,它不应该使用“.decode('windows-1252')”吗? 评论 2011年7月18日19:48
  • 100
    使用“窗口-1252”也不可靠(例如,对于其他语言版本的Windows),最好使用系统.tdout.encoding?
    – 尼科夫
    评论 2012年1月3日15:20
  • 23
    也许这会进一步帮助别人:有时您使用字节数组进行e.x.TCP通信。如果要将字节数组转换为字符串,并去掉尾随的“\x00”字符,以下答案是不够的。然后使用b'example\x00\x00'.decode('utf-8').strip('\x00')。 评论 2013年4月16日13:27
  • 2
    官方文件:为所有人字节字节射线操作(可以在这些对象上调用的方法),请参见:docs.python.org/3/library/stdtypes.html字节-方法。对于字节.decode()具体请参见:docs.python.org/3/library/stdtypes.html字节.decode. 评论 2021年3月25日4:12
  • 1
    just decode()导致utf-8为默认值 评论 2023年12月31日11:14
422

解码字节字符串并将其转换为字符(Unicode)字符串。


Python 3:

编码='utf-8'b'hello'解码(编码)

str(b'hello',编码)

Python 2:

编码='utf-8''hello'解码(编码)

unicode('hello',编码)
1
  • just decode()导致utf-8为默认值 评论 2023年12月31日11:14
263

这会将字节列表合并为字符串:

>>>字节数据=[112,52,52]>>>“”.join(映射(chr,字节数据))“第44页”
  • 9
    @leetNightshade:但它的效率非常低。如果你有一个字节数组,你只需要解码。 评论 2014年9月1日16:25
  • 12
    @萨塞姆:这种方法是一种错误的表达方式:a.解码('latin-1')哪里a=字节射线([112,52,52])(“没有纯文本这样的东西”。如果你成功地将字节转换为文本字符串,那么你使用了一些编码-拉丁素-1在这种情况下)
    – jfs公司
    评论 2016年11月16日3:16
  • 7
    @leetNightshade:为了完整起见:字节(listof_integers).decode('ascii')大约比“”.join(映射(chr,list_of_integers))在Python 3.6上。 评论 2018年7月3日12:01
133

在Python 3中,默认编码为“utf-8”,因此您可以直接使用:

b'hello'.decode()

相当于

b'hello'.decode(编码=“utf-8”)

另一方面,在Python 2中,编码默认为默认的字符串编码。因此,您应该使用:

b'hello'解码(编码)

哪里编码是您想要的编码。

注:Python 2.7中增加了对关键字参数的支持。

1
  • 1
    很好指出decode()w/utf-8是默认值 评论 2023年12月31日11:14
130

如果你不知道编码,那么要以Python 3和Python 2兼容的方式将二进制输入读取为字符串,请使用古老的MS-DOSCP437型编码:

PY3K=系统版本信息>=(3,0)行=[]对于流中线路:如果不是PY3K:lines.append(行)其他:行.追加(行.解码('cp37'))

因为编码未知,所以非英语符号应翻译为的字符cp437编号(英语字符不翻译,因为它们在大多数单字节编码和UTF-8中匹配)。

将任意二进制输入解码为UTF-8是不安全的,因为您可能会得到以下结果:

>>>b“\x00\x01\xffsd”.解码(“utf-8”)回溯(最近一次调用):<模块>中的文件“<stdin>”第1行Unicode解码错误:“utf-8”编解码器无法解码位置2的字节0xff:无效始字节

同样适用于拉丁素-1,这是Python 2的常用选项(默认选项?)。请参阅中的缺失点代码页布局-这是Python因臭名昭著而窒息的地方序号不在范围内.

更新20150604:有传言称Python 3拥有替代景观将数据编码为二进制数据而不会丢失和崩溃的错误策略,但需要进行转换测试,[二进制]->[str]->[二进制],以验证性能和可靠性。

更新20170116:感谢Nearoo的评论-也有可能用斜杠转义所有未知字节反斜杠替换错误处理程序。这仅适用于Python 3,因此即使使用此解决方法,您仍然会从不同的Pythons版本获得不一致的输出:

PY3K=系统版本信息>=(3,0)行=[]对于流中线路:如果不是PY3K:lines.append(行)其他:lines.append(line.decode('utf-8','反斜杠替换'))

请参见Python的Unicode支持了解详细信息。

更新20170119:我决定实现适用于Python 2和Python3的斜杠转义解码。它应该比cp437编号解决方案,但它应该产生相同的结果在每个Python版本上。

#---准备导入编解码器定义斜杠转义(错误):“”“编解码器错误处理程序。err是UnicodeDecode实例。return”用元组替换输入的不可修改部分以及编码应继续的位置“”#打印err,dir(err),err.start,err.end,err.object[:err.start]字节=err.object[err.start:err.end]repl=u'\\x'+十六进制(ord(字节))[2:]return(回复,错误结束)编解码器.register_error('slashescape',slashesape)#---加工流=[b'\x80abc']行=[]对于流中线路:lines.append(line.decode('utf-8','slashescape'))
1
  • 2
    这个答案不正确。latin-1,即ISO-8859-1编码完全能够处理任意二进制数据-字节(范围(256))。解码(“最小-1”)在现代Python版本上运行时没有错误,我想不出它为什么会失败。这个整个点拉丁语-1的特点是它将每个字节映射到Unicode中的前256个代码点,或者说,自1991年第一个版本以来,Unicode的顺序一直被选择,因此前256的代码点将与拉丁语-1匹配。你可能会遇到问题印刷绳子,但那是完全正交的。 评论 2022年7月1日7:15
48

我想你真的想要这个:

>>>从子流程导入*>>>command_stdout=Popen(['ls','-l'],stdout=PIPE).communicate()[0]>>>command_text=command_stdout.decode(编码='windows-1252')

亚伦的回答是正确的,只是你需要知道哪一个要使用的编码。我相信Windows使用“Windows-1252”。只有当您的内容中有一些不寻常的(非ASCII)字符时,这才重要,但这样会有所不同。

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

0
48

因为这个问题实际上是问子流程输出,您可以使用更多直接的方法。最现代的将是使用子流程.检查_输出和传球text=真(Python 3.7+)使用系统默认编码自动解码标准输出:

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

对于Python 3.6,波本接受编码关键词:

>>>从子流程导入Popen,PIPE>>>text=Popen(['ls','-l'],stdout=PIPE,编码='utf-8').communicate()[0]>>>类型(文本)字符串>>>打印(文本)总计0-rw-r--r--1 wim獾0 5月31日12:45 some_file.txt

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

>>>b'abcode'.decode()“abcde”

没有争论,sys.getdefaultencoding()将使用。如果您的数据不是sys.getdefaultencoding(),则必须在解码呼叫:

>>>b'caf\xe9'解码('cp1250')“咖啡馆”
0
38

将universal_newlines设置为True,即。

command_stdout=Popen(['ls','-l'],stdout=PIPE,universal_newlines=True).communicate()[0]
1
  • 3.7日你可以(也应该)做text=真而不是universal_newlines=真.
    – 用户3064538
    评论 2019年1月13日17:02
38

要将字节序列解释为文本,您必须知道对应字符编码:

unicode文本=字节字符串解码(字符编码)

例子:

>>>b'\xc2\xb5'.解码('utf-8')'µ'

最小二乘法命令可能会生成无法解释为文本的输出。文件名Unix上可以是除斜杠以外的任何字节序列b“/”和零b“\0”:

>>>open(字节(范围(0x100)).translate(无,b'\0/'),'w').close()

尝试使用utf-8编码解码这种字节汤会引发问题Unicode解码错误.

情况可能会更糟。解码可能会以静默方式失败并产生乱码如果使用了错误的不兼容编码:

>>>'-'.编码('utf-8').解码('cp1252')'—'

数据已损坏,但您的程序仍不知道故障已经发生。

通常,要使用的字符编码不会嵌入到字节序列本身中。你必须在网上交流这些信息。某些结果比其他结果更有可能发生,因此查德特存在可以猜测字符编码。单个Python脚本可以在不同的位置使用多个字符编码。


最小二乘法可以使用将输出转换为Python字符串os.fsdecode()操作系统即使对于不可编码的文件名(它使用sys.getfilesystemencoding()替代景观上的错误处理程序Unix):

导入操作系统导入子流程output=os.fsdecode(subprocess.check_output('ls'))

要获取原始字节,可以使用操作系统.fsencode().

如果你通过universal_newlines=真参数,然后子流程使用locale.getpreferredencoding(False)解码字节,例如,它可以cp1252型在Windows上。

要实时解码字节流,io.TextIOWrapper()可用于:例子.

不同的命令可能使用不同的字符编码输出,例如。,目录内部命令(cmd公司)可以使用cp437。解码其输出时,可以显式传递编码(Python 3.6+):

output=subprocess.check_output('dir',shell=True,encoding='cp437')

文件名可能与os.listdir()(使用WindowsUnicode API)例如。,“\xb6”可以替换为“\x14”-Python的cp437编解码器映射b'\x14'控制字符U+0014,而不是U+00B6(¶)。要支持使用任意Unicode字符的文件名,请参阅将可能包含非ASCII Unicode字符的PowerShell输出解码为Python字符串

28

While期间@Aaron Maenpaa的回答只要工作,用户最近被问及:

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

您可以使用:

command_stdout.decode()命令

解码()有一个标准论点:

codecs.decode(obj,encoding='utf-8',errors='strit')

0
21

如果出现此错误:

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

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

字节=b“abcdefg”string=bytes.decode(“utf-8”,“忽略”)
20

如果您应该通过尝试获得以下内容解码():

AttributeError:“str”对象没有“decode”属性

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

>>>my_byte_str(我的字节_字符串)b“你好,世界”>>>str(my_byte_str,'utf-8')“你好,世界”
20

字节

m=b“这是字节”

正在转换为字符串

方法1

m.decode(“utf-8”)

m.解码()

方法2

导入编解码器codecs.decode(m,encoding=“utf-8”)

导入编解码器编解码器解码(m)

方法3

str(m,编码=“utf-8”)

str(m)[2:-1]

结果

'这是字节'
17

我们可以使用以下命令解码bytes对象以生成字符串字节解码(编码='utf-8',错误='strit').有关文档,请参阅字节.decode.

Python 3示例:

byte_value=b“abcode”打印(“初始值={}”.format(字节值))print(“初始值type={}”.format(type(byte_value))字符串值=字节值解码(“utf-8”)#这里使用utf-8是因为它是一种非常常见的编码,但您需要使用数据实际使用的编码。打印(“------------”)print(“转换值={}”.format(string_value))print(“转换值type={}”.format(type(string_value))

输出:

初始值=b'abcode'初始值类型=<类“字节”>------------转换值=abcode转换的值类型=

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

8

对于Python 3,这是一个更安全的Pythonic公司转换的方法字节一串:

定义字节到字符串(字节或字符串):if isinstance(bytes_or_str,bytes):#检查是否以字节为单位打印(字节或字符串解码('utf-8'))其他:print(“对象不是字节类型”)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 3 07:00 file2\n’)

输出:

总计0-rw-rw-r--1托马斯托马斯3月0日07:03文件1-rw-rw-r-1托马斯·托马斯3月0日07:03文件2
0
7

使用Windows系统中的数据时(使用\\r\n行尾),我的答案是

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

为什么?使用多行Input.txt尝试此操作:

字节=打开(“Input.txt”,“rb”).read()字符串=字节解码(“utf-8”)open(“Output.txt”,“w”).write(字符串)

所有行尾都将加倍(到\r \r\n),导致额外的空行。Python的文本读取函数通常规范化行尾,以便字符串只使用\n个。如果您从Windows系统接收二进制数据,Python就没有机会这样做。因此,

字节=打开(“Input.txt”,“rb”).read()String=Bytes.decode(“utf-8”).replace(“\r\n”,“\n”)open(“Output.txt”,“w”).write(字符串)

将复制您的原始文件。

0
5

对于您的具体的对于“运行shell命令并将其输出作为文本而不是字节”的情况,在Python3.7上,应该使用子进程.run然后通过text=真(以及capture_output=真捕获输出)

command_result=子进程.run([“ls”,“-l”],capture_output=True,text=True)command_result.stdout#是一个包含程序标准输出的“str”

文本过去被称为通用_新线,并在Python 3.7中进行了更改(嗯,别名)。如果要支持3.7之前的Python版本,请传入universal_newlines=真而不是text=真

发件人sys-系统特定参数和功能:

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

1
  • 5
    子流程的管道为已经二进制缓冲区。您的答案未能解决如何从结果中获取字符串值字节值。 评论 2014年9月1日17:34

试试这个:

字节.从十六进制('c3a9').解码('tf-8')
0
2

转换为字符串而不考虑任何编码类型的最佳方法之一如下-

导入jsonb_string=b“测试字符串”字符串=b_string.decode(json.detect_encoding(b_string)#detect_encoding-用于检测编码)打印(字符串)

这里,我们使用json.detect_编码方法检测编码。

1
def toString(字符串):尝试:返回v.decode(“utf-8”)除ValueError:返回字符串b=b'97.080.500's=“97.080.500”打印(toString(b))打印(到字符串)
  • 1
    虽然此代码可能会回答此问题,但提供了其他上下文关于怎样和/或为什么?它解决了这个问题,将提高答案的长期价值。记住,你是在为未来的读者回答问题,而不仅仅是现在提问的人!拜托编辑您的答案中添加了一个解释,并指出了适用的限制和假设。提到为什么这个答案比其他答案更合适也无妨。
    – 开发-iL
    评论 2018年6月4日5:37
  • 嗨,@Dev-iL,如果你是主持人,你能告诉我主持人是否可以删除像这样毫无意义、空洞、不连贯的答案吗stackoverflow.com/a/68310461/134044
    – 尼尔·G
    评论 2023年1月11日0:00
  • 1
    @我不是主持人(注意,我的昵称旁边没有钻石)。如果你认为一篇帖子质量不高,你应该报告它,如果社区同意你的意见,它就会被删除。
    – 开发-iL
    评论 2023年1月11日8:47
1

如果要转换任何字节,而不仅仅是字符串转换为字节:

使用open(“bytesfile”,“rb”)作为infile:str=base64.b85encode(imageFile.read())以open(“bytesfile”,“rb”)作为infile:str2=json.dumps(列表(infile.read()))

然而,这并不是很有效。它会将2 MB的图片转换为9 MB。

0

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

def bin2str(文本,编码='utf-8'):“”“通过删除所有非Unicode字符将二进制字符串转换为Unicode字符串text:要处理的二进制字符串编码:输出编码*utf-8“”return text.decode(编码,“忽略”)

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

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

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.