Unicode与UTF-8

为了便于阅读后文,这里先介绍一下Unicode标准和UTF-8编码。

Unicode标准

Unicode标准由非盈利组织Unicode联盟维护(https://home.unicode.org/),致力于整理和编码世界上大部分文字系统。Unicode标准最新版为2022年9月发布的15.0.0版本,收录超过14万字符,每个字符都被分配了独一无二的码点(数值编号)。Unicode已经成为ISO国际标准的一部分,最常见的Unicode编码格式有与ASCII兼容的UTF-8和与UCS-2兼容的UTF-16。

Unicode标准将编码空间划分为17个平面,编号从0到16,其中第0平面称为基本多文种平面(BMP,U+0000到U+FFFF),而第1到16平面被称为辅助平面(U+10000到U+10FFFF),这些平面与BMP平面一起至少需要21bit的编码空间,略少于3个字节。BMP平面的码点可以使用单个UTF-16编码单位(2字节)表示,或者使用1~3个字节的UTF-8进行编码;辅助平面的码点在UTF-8中使用4个字节进行编码,在UTF-16中使用4个字节进行编码。

UTF-8编码

出于节省空间等目的,实际上对Unicode标准进行编码有不同实现方式,Unicode的实现方式被称为Unicode转换格式(Unicode Transformation Format,简称为UTF),最常见的当属UTF-8编码,其他实现方式还包括UTF-16(字符用两个字节或四个字节表示)和UTF-32(字符用四个字节表示)等,下面给出一些示例:

字符

Unicode码点

UTF-8编码

a

0x0061

0x61 (1 byte)

0x1EAF

0xe1baaf (3 bytes)

image

0x1D538

0xf09d94b8 (4 bytes)

可以看出Unicode给字符分配的原始码点(编号)和UTF-8具体编码还是有很大不同的,这是因为UTF-8编码以8bit(1字节)为单位对Unicode字符进行变长编码,具体转换规则如下表所示(单元格内首行为16进制表示,次行为2进制表示):

Unicode码点范围(3字节可表示)

UTF-8编码

注释

0x000000 - 0x00007F

00000000 00000000 0zzzzzzz

0x00 - 0x7F

0zzzzzzz

ASCII字符范围,1字节

0x000080 - 0x0007FF

00000000 00000yyy yyzzzzzz

0xC080 - 0xDFBF

110yyyyy 10zzzzzz

第1个字节由110开始,第2个字节由10开始,共2字节

0x000800 - 0x00D7FF

0x00E000 - 0x00FFFF

00000000 xxxxyyyy yyzzzzzz

0xE08080 - 0xEFBFBF

1110xxxx 10yyyyyy 10zzzzzz

第1个字节由1110开始,第2-3个字节由10开始,共3字节

0x010000 - 0x10FFFF

000wwwxx xxxxyyyy yyzzzzzz

0xF0808080 - 0xF7BFBFBF

11110www 10xxxxxx 10yyyyyy 10zzzzzz

第1个字节由11110开始,第2-4个字节由10开始,共4字节

可以看出转换规则其实很直观,就是把Unicode码点对应的数值用3个字节存下来(最多用21个bit),然后根据自己所处的范围将bit位依次填入UTF-8对应空位即可。

汉字的码点空间如下(取自https://www.zhangxinxu.com/study/201611/chinese-language-unicode-range.html),utf16对于BMP平面字符(在下表中Unicode码点仅需两字节的部分)会使用2字节编码,而utf8对于BMP平面的汉字需要使用3字节编码,非BMP平面的汉字utf16和utf8都需要4字节编码。所以如果存储字符基本都是汉字时,utf16字符集的编码长度始终优于或等于utf8字符集的编码长度,可以有效帮助减少存储空间,最多减少1/3的存储空间。

字符集

字数

Unicode码点

基本汉字

20902字

4E00-9FA5

基本汉字补充

38字

9FA6-9FCB

扩展A

6582字

3400-4DB5

扩展B

42711字

20000-2A6D6

扩展C

4149字

2A700-2B734

扩展D

222字

2B740-2B81D

康熙部首

214字

2F00-2FD5

部首扩展

115字

2E80-2EF3

兼容汉字

477字

F900-FAD9

兼容扩展

542字

2F800-2FA1D

PUA(GBK)部件

81字

E815-E86F

部件扩展

452字

E400-E5E8

PUA增补

207字

E600-E6CF

汉字笔画

36字

31C0-31E3

汉字结构

12字

2FF0-2FFB

汉语注音

22字

3105-3120

注音扩展

22字

31A0-31BA

1字

3007

MySQL内支持Unicode标准的Charset

MySQL支持多种Unicode Charset:

  • utf8mb4:使用一到四个字节表示每个字符的Unicode字符集的UTF-8编码。

  • utf8mb3:使用一到三个字节表示每个字符的Unicode字符集的UTF-8编码,仅支持表示基本多文种平面(BMP)。在MySQL 8.0中,这个字符集已被deprecated,应该尽快改用utf8mb4。

  • utf8:utf8mb3的别名。在MySQL 8.0中,这个别名已被deprecated,应改用utf8mb4。预计在未来的版本中,utf8将成为utf8mb4的别名。

  • ucs2:使用两个字节表示每个字符的UCS-2编码,仅支持表示基本多文种平面(BMP)。在MySQL 8.0.28中已被deprecated,预计在未来的版本中将被移除。

  • utf16:使用两个或四个字节表示每个字符的UTF-16编码,类似于UCS-2,但包含了对补充辅助平面的扩展。

  • utf16le:类似于utf16,但是小端序而不是大端序。

  • utf32:使用四个字节表示每个字符的UTF-32编码。