将字节转换为字符串 矫情吗;* 2024-03-30 10:38 13阅读 0赞 ## 问: ## 我将外部程序的标准输出捕获到 bytes 对象中: >>> 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 我尝试了 binascii.b2a\_qp() 方法,但又得到了相同的 bytes 对象: >>> binascii.b2a_qp(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 3 将 bytes 对象转换为 str? ## 答1: ## > huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式 Decode the bytes object 产生一个字符串: >>> b"abcde".decode("utf-8") 'abcde' 上面的示例假设 bytes 对象是 UTF-8,因为它是一种常见的编码。但是,您应该使用数据实际所在的编码! `使用 "windows-1252" 也不可靠(例如,对于其他语言版本的 Windows),使用 sys.stdout.encoding 不是最好吗?` `也许这将进一步帮助某人:有时您使用字节数组进行前 TCP 通信。如果要将字节数组转换为字符串以截断尾随 '\x00' 字符,则以下答案是不够的。然后使用 b'example\x00\x00'.decode('utf-8').strip('\x00') 。` `我在 bugs.python.org/issue17860 填写了一个关于记录它的错误 - 请随时提出补丁。如果很难做出贡献 - 欢迎评论如何改进。` `在 Python 2.7.6 中不处理 b"\x80\x02\x03".decode("utf-8") -> UnicodeDecodeError: 'utf8' codec can't decode byte 0x80 in position 0: invalid start byte。` `如果内容是随机二进制值,则 utf-8 转换可能会失败。请参阅@techtonik 答案(如下)stackoverflow.com/a/27527728/198536` ## 答2: ## > 与HuntsBot一起,探索全球自由职业机会–huntsbot.com 解码字节字符串并将其转换为字符 (Unicode) 字符串。 蟒蛇 3: encoding = 'utf-8' b'hello'.decode(encoding) 或者 str(b'hello', encoding) 蟒蛇2: encoding = 'utf-8' 'hello'.decode(encoding) 或者 unicode('hello', encoding) > huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。 `在 Python 3 上,如果字符串在变量中怎么办?` `@AlaaM .:一样。如果您有 variable = b'hello',那么 unicode_text = variable.decode(character_encoding)` `对我来说,variable = variable.decode() 自动将其转换为我想要的字符串格式。` `@亚历克斯霍尔>首先,您可能有兴趣知道 automagic 使用 utf8,如果您不提供它,它是 encoding arg 的默认值。请参阅bytes.decode` `使用任何解码都会给我: AttributeError: 'str' object has no attribute 'decode'` ## 答3: ## > HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com 这将一个字节列表连接成一个字符串: >>> bytes_data = [112, 52, 52] >>> "".join(map(chr, bytes_data)) 'p44' > huntsbot.com汇聚了国内外优秀的初创产品创意,可按收入、分类等筛选,希望这些产品与实践经验能给您带来灵感。 `谢谢,您的方法对我有用,而其他方法都没有。我有一个未编码的字节数组,需要将其转换为字符串。试图找到一种重新编码它的方法,以便我可以将它解码成一个字符串。这个方法非常有效!` `@leetNightshade:但它的效率非常低。如果你有一个字节数组,你只需要解码。` `@Martijn Pieters 我只是对这些其他答案做了一个简单的基准测试,运行了多次 10,000 次stackoverflow.com/a/3646405/353094,而上述解决方案实际上每次都快得多。在 Python 2.7.7 中运行 10,000 次需要 8 毫秒,而其他运行需要 12 毫秒和 18 毫秒。当然,根据输入、Python 版本等可能会有一些变化。对我来说似乎并不太慢。` `@Sasszem:这种方法是一种变态的表达方式:a.decode('latin-1') where a = bytearray([112, 52, 52])("There Ain't No Such Thing as Plain Text"。如果您设法将字节转换为文本字符串,那么您使用了某种编码 - 在这种情况下为 latin-1)` `对于 python 3,这应该等同于 bytes([112, 52, 52]) - btw bytes 对于局部变量来说是一个坏名字,因为它是 p3 内置的` ## 答4: ## > 打造属于自己的副业,开启自由职业之旅,从huntsbot.com开始! 如果您不知道编码,那么要以 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 "", line 1, in UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 2: invalid start byte 这同样适用于 latin-1,它在 Python 2 中很流行(默认?)。请参阅 Codepage Layout 中的缺失点 - 这是 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’s Unicode Support。 更新 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')) `我真的觉得 Python 应该提供一种机制来替换丢失的符号并继续。` `@techtonik:这不适用于像在 python2 中那样的数组。` `您也可以在 python 3 中使用 b'\x00\x01\xffsd'.decode('utf-8', 'ignore') 忽略 unicode 错误。` `@anatolytechtonik 有可能将转义序列留在字符串中并继续:b'\x80abc'.decode("utf-8", "backslashreplace") 将导致 '\\x80abc'。此信息取自 unicode documentation page,自撰写此答案以来似乎已更新。` `据我对 ISO 8859 系列的理解,ISO 定义仅定义可打印字符,而不是控制代码,这就是为什么您在维基百科的表格中看到空白的原因。然而在实践中,代码 0-31 和 127-159 被映射到相应的 unicode 控制代码。因此,使用 ISO-8859-1(又名 latin1)解码任意字节是安全的(这也适用于某些但并非所有其他 ISO-8859 系列编码)。` ## 答5: ## > huntsbot.com提供全网独家一站式外包任务、远程工作、创意产品分享与订阅服务! In Python 3,默认编码是"utf-8",所以可以直接使用: b'hello'.decode() 这相当于 b'hello'.decode(encoding="utf-8") 另一方面,in Python 2,编码默认为默认字符串编码。因此,您应该使用: b'hello'.decode(encoding) 其中 encoding 是您想要的编码。 Note: 在 Python 2.7 中添加了对关键字参数的支持。 ## 答6: ## > huntsbot.com – 高效赚钱,自由工作 我认为你实际上想要这个: >>> 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 文档(或在此处阅读)。 `open() 用于文本流的函数或 Popen() 如果您传递它 universal_newlines=True 会神奇地为您决定字符编码(Python 3.3+ 中的 locale.getpreferredencoding(False))。` `'latin-1' 是设置了所有代码点的逐字编码,因此您可以使用它来有效地将字节字符串读入 Python 支持的任何类型的字符串(在 Python 2 上逐字读取,在 Python 3 上读取到 Unicode)。` `@tripleee:'latin-1' 是获得 mojibake 的好方法。在 Windows 上也有神奇的替换:将数据从一个进程传送到另一个未修改的进程是非常困难的,例如 dir: \xb6 -> \x14 (the example at the end of my answer)` ## 答7: ## > 保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com 由于这个问题实际上是在询问 subprocess 输出,因此您可以使用更直接的方法。最现代的方法是使用 subprocess.check\_output 并传递 text=True (Python 3.7+) 以使用系统默认编码自动解码标准输出: text = subprocess.check_output(["ls", "-l"], text=True) 对于 Python 3.6,Popen 接受 encoding 关键字: >>> 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 编码解码 ls 输出可能会失败(参见 my answer from 2016 中的示例)。` `@Boris:如果给出 encoding 参数,则忽略 text 参数。` `这是 subprocess 的正确答案。如果您只想等待子流程并获得其结果,也许仍然强调 Popen 几乎总是错误的工具;如文档所述,使用 subprocess.run 或旧功能 check_call 或 check_output 之一。` ## 答8: ## > 与HuntsBot一起,探索全球自由职业机会–huntsbot.com 将universal\_newlines设置为True,即 command_stdout = Popen(['ls', '-l'], stdout=PIPE, universal_newlines=True).communicate()[0] `我一直在使用这种方法,并且有效。虽然,它只是根据系统上的用户偏好来猜测编码,所以它不像其他一些选项那么健壮。这就是它正在做的事情,引用 docs.python.org/3.4/library/subprocess.html:“如果 universal_newlines 为 True,则 [stdin、stdout 和 stderr] 将使用语言环境返回的编码以通用换行符模式作为文本流打开.getpreferredencoding(假)。”` `On 3.7 您可以(并且应该)使用 text=True 而不是 universal_newlines=True。` ## 答9: ## > 一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会 要将字节序列解释为文本,您必须知道相应的字符编码: 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 filenames 也成功(它在 Unix 上使用 sys.getfilesystemencoding() 和 surrogateescape 错误处理程序): import os import subprocess output = os.fsdecode(subprocess.check_output('ls')) 要获取原始字节,您可以使用 os.fsencode()。 如果您传递 universal\_newlines=True 参数,则 subprocess 使用 locale.getpreferredencoding(False) 来解码字节,例如,它可以是 Windows 上的 cp1252。 要即时解码字节流,可以使用 io.TextIOWrapper():example。 不同的命令可能对其输出使用不同的字符编码,例如,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 字符的文件名,请参阅 Decode PowerShell output possibly containing non-ASCII Unicode characters into a Python string ## 答10: ## > 保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com 当 @Aaron Maenpaa’s answer 正常工作时,用户 recently asked: 还有更简单的方法吗? ‘fhand.read().decode(“ASCII”)’ \[…\] 太长了! 您可以使用: command_stdout.decode() decode() 有一个 standard argument: codecs.decode(obj, encoding=‘utf-8’, errors=‘strict’) `使用 'utf-8' 的 .decode() 可能会失败(命令的输出可能使用不同的字符编码,甚至返回不可解码的字节序列)。虽然如果输入是 ascii(utf-8 的子集),那么 .decode() 有效。` ## 答11: ## > huntsbot.com洞察每一个产品背后的需求与收益,从而捕获灵感 如果您应该通过尝试 decode() 获得以下信息: AttributeError:“str”对象没有属性“decode” 您还可以直接在强制转换中指定编码类型: >>> my_byte_str b'Hello World' >>> str(my_byte_str, 'utf-8') 'Hello World' 原文链接:[https://www.huntsbot.com/qa/Vdql/convert-bytes-to-a-string?lang=zh\_CN&from=csdn][https_www.huntsbot.com_qa_Vdql_convert-bytes-to-a-string_lang_zh_CN_from_csdn] > 打造属于自己的副业,开启自由职业之旅,从huntsbot.com开始! [https_www.huntsbot.com_qa_Vdql_convert-bytes-to-a-string_lang_zh_CN_from_csdn]: https://www.huntsbot.com/qa/Vdql/convert-bytes-to-a-string?lang=zh_CN&from=csdn
还没有评论,来说两句吧...