字符串和字节字符串的区别是什么?

我正在使用一个返回“字节字符串”的库;(bytes),我需要将其转换为字符串。

这两者之间真的有区别吗?它们是如何关联的,我该如何进行转换?

242473 次浏览

假设python3(在python2中,这个区别没有那么明确定义)-字符串是一个字符序列,即unicode codepoints;这些都是抽象的概念,不能直接存储在磁盘上。不出意外,字节串是一个字节序列——可以存储在磁盘上的东西。它们之间的映射是编码——有很多这样的类型(可能的有无穷多个)——为了进行转换,你需要知道哪个适用于特定的情况,因为不同的编码可能会将相同的字节映射到不同的字符串:

>>> b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'.decode('utf-16')
'蓏콯캁澽苏'
>>> b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'.decode('utf-8')
'τoρνoς'

一旦你知道使用哪一个,你可以使用字节字符串的.decode()方法从它得到正确的字符串,如上所述。为了完整起见,字符串的.encode()方法则相反:

>>> 'τoρνoς'.encode('utf-8')
b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'

计算机唯一能存储的东西就是字节。

要在计算机中存储任何东西,你必须首先编码它,即将它转换为字节。例如:

  • 如果你想要存储音乐,你必须首先使用MP3WAV编码它。
  • 如果你想要存储一张图片,你必须首先使用PNGJPEG编码它。
  • 如果你想存储文本,你必须首先使用美国信息交换标准代码utf - 8编码它。

MP3、WAV、PNG、JPEG、ASCII和UTF-8都是编码的例子。编码是一种以字节表示音频、图像、文本等的格式。

在Python中,一个字节字符串就是:一个字节序列。它不是人类可读的。在底层,所有内容都必须转换为字节字符串,然后才能存储在计算机中。

另一方面,字符串,通常被称为“字符串”,是一个字符序列。它是人类可读的。字符串不能直接存储在计算机中,它必须首先是编码(转换为字节字符串)。有多种编码可以将字符串转换为字节字符串,例如ASCII和UTF-8。

'I am a string'.encode('ASCII')

上面的Python代码将使用编码ASCII对字符串“我是一根弦”进行编码。上述代码的结果将是一个字节字符串。如果你打印它,Python会将它表示为b'I am a string'。然而,请记住,字节字符串不是人类可读的,只是Python在打印它们时将它们从ASCII解码。在Python中,字节字符串由b表示,后面跟着字节字符串的ASCII表示形式。

字节字符串可以解码变回字符串,如果你知道用于编码它的编码。

b'I am a string'.decode('ASCII')

上面的代码将返回原始字符串'I am a string'

编码和解码是反向操作。所有内容都必须在写入磁盘之前进行编码,并且必须在人类读取之前进行解码。

什么是Unicode?< / >:

从根本上说,计算机只是处理数字。它们通过为每个字母和其他字符分配一个数字来存储它们。

......

Unicode为每个字符提供了一个唯一的数字,无论什么平台,什么程序,什么语言。

因此,当计算机表示一个字符串时,它通过唯一的Unicode编号找到存储在字符串计算机中的字符,这些数字存储在内存中。但是您不能直接将字符串写入磁盘或通过唯一的Unicode数字在网络上传输字符串,因为这些数字只是简单的十进制数字。您应该将字符串编码为字节字符串,例如utf - 8。UTF-8是一种能够编码所有可能字符的字符编码,它将字符存储为字节(它看起来像)。因此编码后的字符串可以在任何地方使用,因为几乎所有地方都支持UTF-8。当您打开来自其他系统的UTF-8编码的文本文件时,您的计算机将对其进行解码,并通过其唯一的Unicode编号显示其中的字符。

当浏览器从网络接收到编码为UTF-8的字符串数据时,它将把数据解码为字符串(假设浏览器采用UTF-8编码)并显示字符串。

在Python 3中,你可以将字符串和字节字符串相互转换:

>>> print('中文'.encode('utf-8'))
b'\xe4\xb8\xad\xe6\x96\x87'
>>> print(b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8'))
中文

总而言之,字符串是在计算机上显示给人类阅读的,字节字符串是用于存储到磁盘和数据传输的。

注意:我将详细阐述我对Python 3的回答,因为Python 2的生命结束非常接近。

Python 3

bytes由8位无符号值的序列组成,而str由表示人类语言文本字符的Unicode码位序列组成。

>>> # bytes
>>> b = b'h\x65llo'
>>> type(b)
<class 'bytes'>
>>> list(b)
[104, 101, 108, 108, 111]
>>> print(b)
b'hello'
>>>
>>> # str
>>> s = 'nai\u0308ve'
>>> type(s)
<class 'str'>
>>> list(s)
['n', 'a', 'i', '̈', 'v', 'e']
>>> print(s)
naïve

尽管bytesstr看起来工作方式相同,但它们的实例彼此不兼容,即bytesstr实例不能与>+这样的操作符一起使用。此外,请记住,比较bytesstr实例是否相等,即使用==,将始终计算为False,即使它们包含完全相同的字符。

>>> # concatenation
>>> b'hi' + b'bye' # this is possible
b'hibye'
>>> 'hi' + 'bye' # this is also possible
'hibye'
>>> b'hi' + 'bye' # this will fail
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't concat str to bytes
>>> 'hi' + b'bye' # this will also fail
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "bytes") to str
>>>
>>> # comparison
>>> b'red' > b'blue' # this is possible
True
>>> 'red'> 'blue' # this is also possible
True
>>> b'red' > 'blue' # you can't compare bytes with str
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'bytes' and 'str'
>>> 'red' > b'blue' # you can't compare str with bytes
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'str' and 'bytes'
>>> b'blue' == 'red' # equality between str and bytes always evaluates to False
False
>>> b'blue' == 'blue' # equality between str and bytes always evaluates to False
False

处理bytesstr时的另一个问题是在处理使用open内置函数返回的文件时。一方面,如果你想从一个文件中读取或写入二进制数据,总是使用二进制模式打开文件,比如'rb'或'wb'。另一方面,如果你想从一个文件中读取或写入Unicode数据,请注意你的计算机的默认编码,因此在必要时传递encoding参数以避免意外。

在Python 2中

str由8位值的序列组成,而unicode由Unicode字符的序列组成。需要记住的一件事是,如果str只包含7位ASCI字符,strunicode可以与操作符一起使用。

在Python 2中使用helper函数在strunicode之间进行转换,在Python 3中使用helper函数在bytesstr之间进行转换可能会很有用。

Unicode是一种公认的字符二进制表示格式和各种格式(例如,小写/大写,换行和回车),以及其他“东西”。(例如,emojis)。无论是在内存中还是在文件中,计算机存储Unicode表示(一系列位)的能力并不亚于存储美国信息交换标准代码表示(不同的一系列位)或任何其他表示(一系列位)的能力。

为了使沟通发生,通信双方必须就将使用的表示形式达成一致。

因为Unicode试图表示人类之间和计算机之间通信中使用的所有可能的字符(和其他“事物”),因此它需要比其他试图表示更有限的字符/事物的表示系统更多的位来表示许多字符(或事物)。“简化”;也许是为了适应历史的使用,Unicode表示法几乎完全被转换为其他表示法系统(例如ASCII),以便在文件中存储字符。

Unicode 不能不是用于在文件中存储字符或通过任何通信通道传输字符的情况。它只是 not。

术语“字符串”,“;并不是精确定义的。“弦,“在其常用用法中,指的是一组字符/事物。在计算机中,这些字符可以存储在许多不同的位-位表示形式中的任何一种。字节字符串;是一组使用使用8位(8位称为一个字节)的表示来存储的字符。由于现在计算机使用Unicode系统(由可变字节数表示的字符)将字符存储在内存中,使用字节字符串(由单个字节表示的字符)将字符存储到文件中,因此在将内存中表示的字符移动到文件中存储之前必须使用转换。

让我们有一个简单的单字符字符串'š',并将其编码为一个字节序列:

>>> 'š'.encode('utf-8')
b'\xc5\xa1'

为了本例的目的,让我们以二进制形式显示字节序列:

>>> bin(int(b'\xc5\xa1'.hex(), 16))
'0b1100010110100001'

现在是一般不可能来解码信息,而不知道它是如何编码的。只有当你知道使用了UTF-8文本编码时,你才能根据解码UTF-8的算法获取原始字符串:

11000101 10100001
^^^^^   ^^^^^^
00101   100001

你可以将二进制数101100001显示为字符串:

>>> chr(int('101100001', 2))
'š'

Python语言包括strbytes作为标准的“内置类型”。换句话说,它们都是类。我认为没有必要去解释为什么Python以这种方式实现。

话虽如此,strbytes彼此非常相似。两者都有大部分相同的方法。以下方法对于str类是唯一的:

casefold
encode
format
format_map
isdecimal
isidentifier
isnumeric
isprintable

以下方法对于bytes类是唯一的:

decode
fromhex
hex

简单地说,想想我们的自然语言,如英语、孟加拉语、汉语等。在说话时,所有这些语言都发出声音。但即使我们听到了,我们能听懂所有的吗?-

答案通常是否定的。所以,如果我说我懂英语,这意味着我知道这些声音是如何被编码成一些有意义的英语单词的,我只是用同样的方式解码这些声音来理解它们。所以,其他语言也是如此。如果你知道它,你就有了那种语言的编码器-解码器包,如果你不知道它,你就没有这个。

数字系统也是如此。就像我们自己一样,我们只能用耳朵听声音,用嘴巴发声,计算机只能存储字节和读取字节。因此,某个应用程序知道如何读取字节并解释它们(比如要考虑多少字节才能理解任何信息),并且以相同的方式编写,以便其其他应用程序也能理解它。但是如果没有理解(编码器-解码器),所有写入磁盘的数据都只是字节串。

字符串是串在一起的一堆项目。字节串是一个字节序列,比如b'\xce\xb1\xce\xac'表示"αά"。字符串是一串字符,比如"αά"。序列的同义词。

字节串可以直接存储在磁盘上,而字符串(字符串)不能直接存储在磁盘上。它们之间的映射是一种编码。