要将字节序列解释为文本,您需要知道相应的字符编码:
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
错误。
情况可能更糟。如果您使用不兼容的错误编码,则解码可能会默默失败并产生乱码:
>>> '—'.encode('utf-8').decode('cp1252')
'—'
数据已损坏,但您的程序仍然不知道故障已发生。
通常,要使用哪种字符编码并未嵌入在字节序列本身中。您必须通过外带信息来传达此信息。一些结果比其他结果更有可能,因此存在可以“猜测”字符编码的
chardet
模块。单个Python脚本可能在不同的位置使用多个字符编码。
ls
输出可以使用os.fsdecode()
函数转换为Python字符串,即使对于无法解码的文件名也是如此(它在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()
:
示例。
不同的命令可能使用不同的字符编码进行其输出,例如,
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字符串。
str(text_bytes)
不起作用?这对我来说似乎很奇怪。 - Charlie Parkerstr(text_bytes)
无法指定编码方式。根据text_bytes
中包含的内容,使用text_bytes.decode('cp1250')
可能会得到与text_bytes.decode('utf-8')
截然不同的字符串。 - Craig Andersonstr
函数不再自动将其它类型转换为字符串。由于某些原因,必须显式指定编码方式。只需要将编码方式设置为utf-8
并检查你的代码是否正常工作即可。例如:var = var.decode('utf-8')
。 - Charlie Parkerunicode_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') != '¶'
。 - jfstext=True
传递给subprocess.run()
或.Popen()
,然后您将获得一个字符串,无需转换字节。或者在任一函数中指定encoding="utf-8"
。 - David Gilbertsonstr(<bytes>)
时得到的字符串的用例,但也许只是为了与其他str
调用保持一致。我本以为它们可以默认为UTF-8编码,但也许是因为Windows有太多奇怪的编码方式,所以它不会默认为UTF-8;但我同意你的观点。 - NeilG