当前位置:  开发笔记 > 编程语言 > 正文

将字节转换为字符串?

如何解决《将字节转换为字符串?》经验,为你挑选了12个好方法。

我正在使用此代码从外部程序获取标准输出:

>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]

communic()方法返回一个字节数组:

>>> 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()方法的用途,但是当我尝试它时,我又得到了相同的字节数组:

>>> 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.



1> Aaron Maenpa..:

您需要解码bytes对象以生成字符串:

>>> b"abcde"
b'abcde'

# utf-8 is used here because it is a very common encoding, but you
# need to use the encoding your data is actually in.
>>> b"abcde".decode("utf-8") 
'abcde'


使用"windows-1252"`也不可靠(例如,对于Windows的其他语言版本),最好不要使用`sys.stdout.encoding`?
在Python 2.7.6中不处理`b"\ x80\x02\x03".decode("utf-8")` - >`UnicodeDecodeError:'utf8'编解码器无法解码位置0的字节0x80:无效启动byte`.
也许这会对某些人有所帮助:有时你使用字节数组进行TCP通信.如果要将字节数组转换为字符串,请删除尾随的'\ x00'字符,以下答案是不够的.使用b'example\x00\x00'.decode('utf-8').strip('\ x00')然后.
如果内容是随机二进制值,则"utf-8"转换可能会失败.请参阅@techtonik答案(如下)http://stackoverflow.com/a/27527728/198536
我已经在http://bugs.python.org/issue17860上填写了有关记录此文档的错误-随时提出补丁。如果很难做出贡献,欢迎评论如何改进。

2> dF...:

您需要解码字节字符串并将其转换为字符(unicode)字符串.

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

或者在Python 3上

unicode('hello', encoding)



3> Sisso..:

我觉得这很简单:

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


@Martijn Pieters我刚刚用这些其他答案做了一个简单的基准测试,运行多次10,000次运行http://stackoverflow.com/a/3646405/353094而且上述解决方案实际上每次都要快得多.对于Python 2.7.7中的10,000次运行,需要8ms,而其他运行时间为12ms和18ms.当然,根据输入,Python版本等可能存在一些变化.对我来说似乎不太慢.
谢谢,你的方法对我来说很有效.我有一个非编码的字节数组,我需要变成一个字符串.试图找到一种方法来重新编码它,以便我可以将其解码为字符串.这种方法效果很好!
@leetNightshade:但效率非常低.如果你有一个字节数组,你只需要解码.
@Martijn Pieters是的.因此,就这一点而言,这不是问题正文的最佳答案.标题是误导,不是吗?他/她想将字节字符串转换为常规字符串,而不是将字节数组转换为字符串.这个答案适用于所提问题的标题.
对于python 3,这应该相当于[`bytes([112,52,52])`](/sf/ask/17360801/) - btw字节对于局部变量来说是一个坏名称,因为这是一个内置的p3
@Sasszem:此方法是一种变态的表达方式:`a.decode('latin-1')`其中`a = bytearray([112,52,52])`((“”没有这样的东西纯文本”](http://www.joelonsoftware.com/articles/Unicode.html。如果您设法将字节转换为文本字符串,则可以使用某种编码-在这种情况下为“ latin-1”)

4> anatoly tech..:

如果您不知道编码,那么要以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的流行(默认?).请参阅代码页布局中的缺失点- 这是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'))

有关详细信息,请参阅https://docs.python.org/3/howto/unicode.html#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应该提供一种机制来替换丢失的符号并继续.
@anatolytechtonik有可能将转义序列留在字符串中继续前进:`b'\ x80abc'.decode("utf-8","backslashreplace")`将导致''\\ x80abc'.此信息来自[unicode文档页面](https://docs.python.org/3/howto/unicode.html#python-s-unicode-support),该答案自编写此答案后似乎已更新.
辉煌!对于256 MB的文件,这比@Sisso的方法快得多!

5> lmiguelvarga..:

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

b'hello'.decode()

这相当于

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

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

b'hello'.decode(encoding)

encoding你想要的编码在哪里.

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



6> mcherm..:

我想你真正想要的是:

>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
>>> command_text = command_stdout.decode(encoding='windows-1252')

Aaron的回答是正确的,除了你需要知道要使用的WHICH编码.我相信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)。

7> 小智..:

将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]将使用locale返回的编码以通用换行模式打开文本流.getpreferredencoding(假)".

8> serv-inc..:

虽然@Aaron Maenpaa的答案正常,但是一位用户最近问道

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

您可以使用

command_stdout.decode()

decode()有一个标准的论点

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



9> wim..:

由于这个问题实际上是在询问subprocess输出,因此您可以使用更直接的方法,因为它Popen接受了一个编码关键字(在Python 3.6+中):

>>> 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é'


或使用Python 3.7,您可以通过[`text = True`](https://docs.python.org/3/library/subprocess.html#subprocess.Popen)使用给定的编码来解码stdin,stdout和stderr(如果设置),否则系统默认设置。Popen(['ls','-l'],stdout = PIPE,text = True)

10> jfs..:

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

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字符串(它在Unix上使用 sys.getfilesystemencoding()surrogateescape错误处理程序):

import os
import subprocess

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

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

如果您传递universal_newlines=True参数然后subprocess用于 locale.getpreferredencoding(False)解码字节,例如,它可以 cp1252在Windows上.

要动态解码字节流, 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字符的文件名,请参阅将 可能包含非ascii unicode字符的powehell输出解码为python字符串



11> Broper..:

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

decode()

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

>>> my_byte_str
b'Hello World'

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



12> bers..:

当使用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)

将复制您的原始文件。

推荐阅读
个性2402852463
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有