Python中的bytes对象以及UTF-8编码
看了 `bytes`: The Lesser-Known Python Built-In Sequence • And Understanding UTF-8 Encoding 之后自己尝试了一下中文,加深了对UTF-8的一点点理解.
Python的bytes对象
bytes
是由单个字节构成的不可变整数序列。序列中的每个值的大小被限制为 0 <= x < 256 (如果违反此限制将引发 ValueError
)。
bytes
对象和 str
对象都是序列,他们的输出非常相似,只不过 bytes
的输出多了前面的b和单引号:
text = "Hello"
text_bytes = b"Hello"
print(text)
print(text_bytes)
Hello b'Hello'
但他们也有一些区别:
text = "Hello"
text_bytes = b"Hello"
print(list(text))
print(list(text_bytes))
['H', 'e', 'l', 'l', 'o'] [72, 101, 108, 108, 111]
和 str
中存放的是字符本身不一样, bytes
中存放的是字符的数字编码。
UTF-8编码
Unicode,全称为Unicode标准(The Unicode Standard),其官方机构Unicode联盟所用的中文名称为统一码[1],又译作万国码、统一字符码、统一字符编码[2],是信息技术领域的业界标准,其整理、编码了世界上大部分的文字系统,使得电脑能以通用划一的字符集来处理和显示文字,不但减轻在不同编码系统间切换和转换的困扰,更提供了一种跨平台的乱码问题解决方案,已经收录超过14万个字符。
UTF-8是UNICODE中最常见的一种编码,它是一种可变长度的编码表达方式,为了与以前的ASCII码兼容(ASCII为一个字节,前128个Unicode字符与ASCII字符匹配)。UTF-8将代码点编码为一到四个字节,具体取决于代码点的值。在下表中,x字符表示可用于编码的的位:
de point | Last code point | Byte 1 | Byte 2 | Byte 3 | Byte 4 |
U+0000 | U+007F | 0xxxxxxx | |||
U+0080 | U+07FF | 110xxxxx | 10xxxxxx | ||
U+0800 | U+FFFF | 1110xxxx | 10xxxxxx | 10xxxxxx | |
U+010000 | U+10FFFF | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
上表中如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。
以"中"字为例,它的UNICODE编码为 \u4e2d
,让我们通过 bytes
来看看UTF-8是如何编码的:
text_bytes = bytes("中", "utf-8")
print(f"{text_bytes=}")
print(f"{len(text_bytes)=}")
print(f"{list(text_bytes)=}")
binary_list = [bin(x)[2:] for x in list(text_bytes)]
print(f"{binary_list=}")
text_bytes=b'\xe4\xb8\xad' len(text_bytes)=3 list(text_bytes)=[228, 184, 173] binary_list=['11100100', '10111000', '10101101']
最终获取到的三个字节内容分别是 ['11100100', '10111000', '10101101']
,按照UTF-8编码的规则,第一个字符3个连续的1表示这个字符占3个字节,第一个字节用来表示字符编码的是 0100
,第二个字节用来表示字符编码的是 111000
,第三个字节用来表示字符编码的是 101101
,这样组合起来的字符编码就是 0100_1110_0010_1101
,转换成十六进制就是 4e2d
。
可变的bytes
bytes
是不可变序列,如果尝试修改 bytes
中的某个索引位置的值,可以用 bytearray
对象。下面是一个示例:
char = bytearray(list([228,184,173]))
print(f"before: {char.decode("utf-8")}")
char[0] = 229
print(f"after: {char.decode("utf-8")}")
before: 中 after: 席
小结
bytes
是由单个字节构成的不可变整数序列,存放的是字符的编码数字。- UTF-8 是一种可变长度的编码表达方式,长度包含1到4个字节。根据第一个字节的左边第一个0左边的连续的1的个数来表示这个字符一共用了几个字节。每个字节左起第一个0右边的数位表示字符的Unicode编码。
bytes
是不可变序列,如果需要可变的bytes
,用bytearray
。