我正在使用一个库,该库返回一个";字节串";(bytes
),我需要将其转换为字符串。
这两件事真的有区别吗?它们是如何关联的,我如何进行转换?
计算机唯一能存储的就是字节。
要在计算机中存储任何内容,必须首先对其进行编码,即将其转换为字节。例如:
- 如果您想存储音乐,您必须首先使用MP3、WAV等对进行编码
- 如果要存储图片,必须首先使用PNG、JPEG等对图片进行编码
- 如果要存储文本,必须首先使用ASCII、UTF-8等对进行编码
MP3、WAV、PNG、JPEG、ASCII和UTF-8是编码的示例。编码是一种以字节表示音频、图像、文本等的格式。
在Python中,字节字符串就是这样:一个字节序列。它不是人类可读的。在引擎盖下,所有东西都必须转换成字节字符串才能存储在计算机中。
另一方面,一个字符串,通常只是被称为"字符串";,是一个字符序列。它是人类可读的。字符串不能直接存储在计算机中,必须先对其进行编码(转换为字节字符串)。有多种编码可以将字符串转换为字节字符串,例如ASCII和UTF-8。
'I am a string'.encode('ASCII')
上面的Python代码将使用编码ASCII对字符串"I am a string"进行编码。上面代码的结果将是一个字节字符串。如果打印它,Python将把它表示为b'I am a string'
。然而,请记住,字节字符串不是人类可读的,只是当您打印它们时,Python会从ASCII中解码它们。在Python中,字节字符串由b
表示,后跟字节字符串的ASCII表示。
如果你知道用于编码的编码,字节字符串可以被解码为字符串。
b'I am a string'.decode('ASCII')
上述代码将返回原始字符串'I am a string'
。
编码和解码是相反的操作。所有东西都必须经过编码才能写入磁盘,必须经过解码才能被人类读取。
假设Python 3(在Python 2中,这种差异定义不太明确)-字符串是一个字符序列,即unicode代码点;这些都是一个抽象的概念,不能直接存储在磁盘上。毫不奇怪,字节字符串是字节的序列,可以存储在磁盘上。它们之间的映射是编码-有很多这样的编码(可能有无限多)-为了进行转换,你需要知道哪种编码适用于特定情况,因为不同的编码可能会将相同的字节映射到不同的字符串:
>>> b'xcfx84oxcfx81xcexbdoxcfx82'.decode('utf-16')
'蓏콯캁澽苏'
>>> b'xcfx84oxcfx81xcexbdoxcfx82'.decode('utf-8')
'τoρνoς'
一旦您知道要使用哪一个,就可以使用字节字符串的.decode()
方法从中获得正确的字符串,如上所述。为了完整性,字符串的.encode()
方法走相反的路:
>>> 'τoρνoς'.encode('utf-8')
b'xcfx84oxcfx81xcexbdoxcfx82'
注意:我将详细阐述我对Python 3的答案,因为Python 2的生命即将结束。
在Python 3中
bytes
由8位无符号值序列组成,而str
由表示人类语言文本字符的Unicode代码点序列组成。
>>> # bytes
>>> b = b'hx65llo'
>>> type(b)
<class 'bytes'>
>>> list(b)
[104, 101, 108, 108, 111]
>>> print(b)
b'hello'
>>>
>>> # str
>>> s = 'naiu0308ve'
>>> type(s)
<class 'str'>
>>> list(s)
['n', 'a', 'i', '̈', 'v', 'e']
>>> print(s)
naïve
尽管bytes
和str
的工作方式似乎相同,但它们的实例彼此不兼容,即bytes
和str
实例不能与>
和+
等运算符一起使用。此外,请记住,比较bytes
和str
实例是否相等,即使用==
,即使它们包含完全相同的字符,也将始终计算为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
处理bytes
和str
时的另一个问题是在处理使用open
内置函数返回的文件时出现的。一方面,如果您想在文件中读取或写入二进制数据,请始终使用二进制模式(如"rb"或"wb")打开文件。另一方面,如果您想在文件中读取或写入Unicode数据,请注意计算机的默认编码,因此在必要时传递encoding
参数以避免意外。
在Python 2中
str
由8位值的序列组成,而unicode
由Unicode字符的序列组成。需要记住的一点是,如果str
仅由7位ASCI字符组成,则str
和unicode
可以与运算符一起使用。
使用辅助函数在Python 2中的str
和unicode
之间以及在Python 3中的bytes
和str
之间进行转换可能会很有用。
让我们有一个简单的单字符字符串'š'
,并将其编码为字节序列:
>>> 'š'.encode('utf-8')
b'xc5xa1'
为了这个例子的目的,让我们以二进制形式显示字节序列:
>>> bin(int(b'xc5xa1'.hex(), 16))
'0b1100010110100001'
现在,在不知道信息是如何编码的情况下,通常不可能对信息进行解码。只有当你知道使用了UTF-8文本编码时,你才能按照UTF-8解码的算法获得原始字符串:
11000101 10100001
^^^^^ ^^^^^^
00101 100001
您可以将二进制数字101100001
显示为字符串:
>>> chr(int('101100001', 2))
'š'
从什么是Unicode:
从根本上讲,计算机只处理数字。它们通过为每个字符指定一个数字来存储字母和其他字符。
Unicode为每个字符提供了一个唯一的数字,无论平台是什么,无论程序是什么,也无论语言是什么。
因此,当计算机表示字符串时,它会通过其唯一的Unicode编号找到存储在字符串计算机中的字符,这些数字会存储在内存中。但您不能直接将字符串写入磁盘,也不能通过其唯一的Unicode数字在网络上传输字符串,因为这些数字只是简单的十进制数字。您应该将字符串编码为字节字符串,例如UTF-8。UTF-8是一种能够对所有可能的字符进行编码的字符编码,它将字符存储为字节(看起来像这样)。因此,编码字符串可以在任何地方使用,因为UTF-8几乎在任何地方都受支持。当您从其他系统打开以UTF-8编码的文本文件时,您的计算机将对其进行解码,并通过其唯一的Unicode编号显示其中的字符。
当浏览器从网络接收到UTF-8编码的字符串数据时,它会将数据解码为字符串(假设浏览器使用UTF-8编码)并显示字符串。
在Python3中,可以将字符串和字节字符串相互转换:
>>> print('中文'.encode('utf-8'))
b'xe4xb8xadxe6x96x87'
>>> print(b'xe4xb8xadxe6x96x87'.decode('utf-8'))
中文
总之,字符串用于在计算机上显示给人类阅读,字节字符串用于存储到磁盘和数据传输。
Unicode是一种商定的字符二进制表示格式和各种格式(例如,小写/大写、换行和回车),以及其他";事物;(例如表情符号)。计算机存储Unicode表示(一系列位)的能力,无论是在内存中还是在文件中,都不亚于存储ASCII表示(不同的位系列)或任何其他表示(位系列)的能力。
为了进行通信,通信各方必须就使用何种表示达成一致。
由于Unicode试图表示人与人之间和计算机之间通信中使用的所有字符(以及其他"事物"),因此与其他试图表示更有限的字符/事物集的表示系统相比,它需要更多的比特来表示许多字符(或事物)。致";简化;也许为了适应历史使用,Unicode表示几乎完全转换为其他表示系统(例如ASCII),用于在文件中存储字符。
Unicode不能用于在文件中存储字符,或通过任何通信通道传输字符。很简单,它不是。
术语";字符串,";不是精确定义的"字符串,";在其常用用法中,指的是一组字符/事物。在计算机中,这些字符可以存储在许多不同的逐位表示中的任何一个中。A";字节串";是使用使用八位(八位被称为字节)的表示存储的一组字符。由于如今,计算机使用Unicode系统(由可变字节数表示的字符)将字符存储在内存中,使用字节串(由单个字节表示的字符。
字符串是一串串在一起的项目。字节串是一个字节序列,类似于代表"αά"
的b'xcexb1xcexac'
。字符串是一组字符,如"αά"
。序列的同义词。
字节字符串可以直接存储到磁盘上,而字符串(字符串)不能直接存储在磁盘上。它们之间的映射是一种编码。
简单地说,想想我们的自然语言,比如英语、孟加拉语、汉语等。在说话时,所有这些语言都会发出声音。但是,即使我们听到它们,我们也能理解它们吗?-
答案通常是否定的。所以,如果我说我理解英语,这意味着我知道这些声音是如何编码成一些有意义的英语单词的,我只是用同样的方式解码这些声音来理解它们。因此,任何其他语言也是如此。如果你知道,你脑海中就有了该语言的编码器-解码器包,如果你不知道,你就是没有这个。
数字系统也是如此。就像我们自己一样,由于我们只能用耳朵听声音,用嘴发声,计算机只能存储字节和读取字节。因此,某个应用程序知道如何读取和解释字节(比如要考虑多少字节才能理解任何信息),也知道如何以同样的方式写入,以便其他应用程序也能理解。但如果不理解(编码器-解码器),所有写入磁盘的数据都只是字节串。
Python语言包括标准的str
和bytes
;内置类型";。换句话说,它们都是类。我认为不值得试图解释为什么Python是以这种方式实现的。
话虽如此,str
和bytes
彼此非常相似。两者的方法大多相同。以下方法是str
类独有的:
casefold
encode
format
format_map
isdecimal
isidentifier
isnumeric
isprintable
以下方法是bytes
类独有的:
decode
fromhex
hex