将字节转换为字符串

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

>>> from subprocess import *>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]>>>>>> command_stdoutb'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将bytes对象转换为str

4477700 次浏览

解码#0对象生成一个字符串:

>>> b"abcde".decode("utf-8")'abcde'

上面的示例假设表明bytes对象是UTF-8,因为它是一种常见的编码。但是,您应该使用数据实际使用的编码!

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


python3:

encoding = 'utf-8'b'hello'.decode(encoding)

str(b'hello', encoding)

python2:

encoding = 'utf-8''hello'.decode(encoding)

unicode('hello', encoding)

我想你真的想要这个:

>>> 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留档(或在这里阅读)。

这将字节列表连接到一个字符串中:

>>> bytes_data = [112, 52, 52]>>> "".join(map(chr, bytes_data))'p44'

sys-系统特定的参数和函数

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

将universal_newlines设为True,即。

command_stdout = Popen(['ls', '-l'], stdout=PIPE, universal_newlines=True).communicate()[0]

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

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: invalidstart byte

这同样适用于latin-1,它在Python 2中很受欢迎(默认?)。请参阅代码页布局中的缺失点-这是Python被臭名昭著的ordinal not in range窒息的地方。

更新20150604:有传言称Python 3具有surrogateescape错误策略,可以将内容编码为二进制数据而不会丢失和崩溃,但它需要转换测试[binary] -> [str] -> [binary]来验证性能和可靠性。

更新20170116:感谢Nerioo的评论-也有可能使用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. returna tuple with a replacement for the unencodable part of the inputand 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'))

虽然@Aaron Maenpaa的回答只是工作,但用户最近问

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

您可以使用:

command_stdout.decode()

decode()有一个标准论证

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

在python3,默认编码为"utf-8",因此您可以直接使用:

b'hello'.decode()

这相当于

b'hello'.decode(encoding="utf-8")

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

b'hello'.decode(encoding)

其中encoding是您想要的编码。

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

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

unicode_text = bytestring.decode(character_encoding)

示例:

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

ls命令可能会产生无法解释为文本的输出。文件名在Unix上可以是除斜杠b'/'和零之外的任何字节序列b'\0'

#请求参数
>>> open(bytes(range(0x100)).translate(None, b'\0/'), 'w').close()

尝试使用utf-8编码解码这样的字节汤会引发UnicodeDecodeError

情况可能更糟。解码可能会无声无息地失败并产生mojibake如果您使用错误的不兼容编码:

>>> '—'.encode('utf-8').decode('cp1252')'—'

数据已损坏,但您的程序仍然不知道失败发生了

一般来说,要使用的字符编码并不嵌入在字节序列本身中。您必须在带外传达此信息。一些结果比其他结果更有可能,因此存在chardet模块可以字符编码。单个Python脚本可能在不同的地方使用多个字符编码。


ls输出可以使用os.fsdecode()转换为Python字符串成功的函数甚至为undecodable文件名(它使用sys.getfilesystemencoding()surrogateescape错误处理程序Unix系统:

import osimport subprocess
output = os.fsdecode(subprocess.check_output('ls'))

要获取原始字节,您可以使用os.fsencode()

如果传递universal_newlines=True参数,则subprocess使用locale.getpreferredencoding(False)解码字节,例如,它可以是cp1252在Windows上。

要动态解码字节流,io.TextIOWrapper()可以使用:示例

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

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

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

对于Python 3,这是从byte转换为string的更安全和Pythonic的方法:

def byte_to_str(bytes_or_str):if isinstance(bytes_or_str, bytes): # Check if it's in bytesprint(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

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

属性错误:“str”对象没有属性“解码”

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

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

当处理来自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)

将复制您的原始文件。

由于这个问题实际上是询问subprocess输出,因此你有更直接的方法可用。最现代的方法是使用#1并传递text=True(Python 3.7+)使用系统默认编码自动解码标准输出:

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'

没有参数,将使用#0。如果您的数据不是sys.getdefaultencoding(),那么您必须在#2调用中显式指定编码:

>>> b'caf\xe9'.decode('cp1250')'café'
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))

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

with open("bytesfile", "rb") as infile:str = base64.b85encode(imageFile.read())
with open("bytesfile", "rb") as infile:str2 = json.dumps(list(infile.read()))

然而,这不是很有效。它会将2 MB的图片变成9 MB。

对于特定的情况“运行shell命令并将其输出作为文本而不是字节”,在Python 3.7上,您应该使用#0并传入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中被更改(好吧,别名)。如果您想支持3.7之前的Python版本,请传入universal_newlines=True而不是text=True

试试这个:

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

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

def bin2str(text, encoding = 'utf-8'):"""Converts a binary to Unicode string by removing all non Unicode chartext: binary string to work onencoding: output encoding *utf-8"""
return text.decode(encoding, 'ignore')

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

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

使用.decode()解码。这将解码字符串。传入'utf-8')作为内部的值。

如果您遇到此错误:

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

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

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

我们可以使用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 = abcdeConverted value type = <class 'str'>

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

字节数

m=b'This is bytes'

转换为字符串

方法1

m.decode("utf-8")

m.decode()

方法2

import codecscodecs.decode(m,encoding="utf-8")

import codecscodecs.decode(m)

方法3

str(m,encoding="utf-8")

str(m)[2:-1]

结果

'This is bytes'