目录

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