Unicode 编码标准介绍
UTF-8、UTF-16 和 UTF-32 都是 Unicode 编码 的不同实现方式,它们各自有不同的设计思想,适用于不同的存储和传输场景。我们可以从比特(bit)层面仔细看一下它们的编码设计。
1. UTF-8 编码
UTF-8 是一种变长编码方式,支持的字符范围从 U+0000 到 U+10FFFF。它根据字符的 Unicode 码点(即字符的编号)使用 1 至 4 个字节来编码一个字符。UTF-8 的设计思想是通过 字节的高位 来标识当前字符需要多少个字节来表示。
设计规则
- UTF-8 使用 1 到 4 个字节,并且每个字节的高位被用作标记当前字符是否需要后续字节。
- 对于每个字节,前几个比特用于表示字符的信息,剩余比特用于续字节标记。
具体的编码规则如下:
-
1 字节(7 位字符):
- 对于 U+0000 到 U+007F 范围内的字符(即基本的 ASCII 字符),UTF-8 使用 1 个字节。
- 结构:
0xxxxxxx(7 个有效位) - 例如:字符
A(U+0041)在 UTF-8 中编码为0x41(即01000001)
-
2 字节(11 位字符):
- 对于 U+0080 到 U+07FF 范围内的字符,使用 2 个字节。
- 结构:
110xxxxx 10xxxxxx(前导字节标志为110,续字节标志为10) - 例如:字符
é(U+00E9)在 UTF-8 中编码为0xC3 0xA9(即11000011 10101001)
-
3 字节(16 位字符):
- 对于 U+0800 到 U+FFFF 范围内的字符,使用 3 个字节。
- 结构:
1110xxxx 10xxxxxx 10xxxxxx(前导字节标志为1110,续字节标志为10) - 例如:字符
中(U+4E2D)在 UTF-8 中编码为0xE4 0xB8 0xAD(即11100100 10111000 10101101)
-
4 字节(21 位字符):
- 对于 U+10000 到 U+10FFFF 范围内的字符,使用 4 个字节。
- 结构:
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx(前导字节标志为11110,续字节标志为10) - 例如:字符
𐍈(U+10348)在 UTF-8 中编码为0xF0 0x90 0x8D 0x88(即11110000 10010000 10001101 10001000)
总结
- UTF-8 使用 1 到 4 字节 来编码字符,每个字节的高位用于标识是否是续字节。
- 字节结构:
- 1 字节:
0xxxxxxx - 2 字节:
110xxxxx 10xxxxxx - 3 字节:
1110xxxx 10xxxxxx 10xxxxxx - 4 字节:
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- 1 字节:
2. UTF-16 编码
UTF-16 是一种变长编码方式,使用 2 或 4 个字节 来表示字符。UTF-16 使用 16 位 来表示字符,支持的字符范围从 U+0000 到 U+10FFFF。对于超出 BMP(基本多文种平面,U+0000 到 U+FFFF)的字符,UTF-16 使用 代理对(surrogate pairs) 机制来表示。
设计规则
-
U+0000 到 U+FFFF:使用 1 个 16 位单元(2 字节)。
- 结构:
00000000 00000000(16 位) - 例如:字符
A(U+0041)在 UTF-16 中编码为0x0041(即00000000 01000001)
- 结构:
-
U+10000 到 U+10FFFF:这些字符超出了 16 位,需要使用 2 个 16 位单元(4 字节),即 代理对(surrogate pairs)。
- 代理对的计算方式:
- 首先从字符的码点中减去 0x10000(得到 20 位数)。
- 然后将其分成两个部分:
- 高位(高代理项):
0xD800 | (high 10 bits) - 低位(低代理项):
0xDC00 | (low 10 bits)
- 高位(高代理项):
- 例如:字符
𐍈(U+10348):- 减去
0x10000:U+10348 - 0x10000 = 0x0348(20 位) - 高位:
0xD800 | (0x0348 >> 10) = 0xD800 | 0x0003 = 0xD803 - 低位:
0xDC00 | (0x0348 & 0x3FF) = 0xDC00 | 0x348 = 0xDC48 - UTF-16 编码为
0xD803 0xDC48(即11010111 10000011 11011100 01001000)
- 减去
- 代理对的计算方式:
总结
- UTF-16 使用 2 字节 表示字符(BMP 字符),并使用 代理对(两个 16 位单元,共 4 字节)表示超出 BMP 的字符。
- 字符范围:
- 1 单元(2 字节):
00000000 00000000 - 2 单元(4 字节,代理对):
110110xxxx xxxx 110111xxxx xxxx
- 1 单元(2 字节):
3. UTF-32 编码
UTF-32 是一种固定长度的编码方式,使用 4 个字节(即 32 位)来表示字符。它可以直接表示所有的 Unicode 字符,不需要变长或代理对。
设计规则
- U+0000 到 U+10FFFF:每个字符都用 4 字节 表示。
- 结构:
00000000 00000000 00000000 xxxxxxxx(32 位) - 例如:字符
A(U+0041)在 UTF-32 中编码为0x00000041(即00000000 00000000 00000000 01000001) - 例如:字符
中(U+4E2D)在 UTF-32 中编码为0x00004E2D(即00000000 00000000 01001110 00101101)
- 结构:
总结
- UTF-32 使用 4 字节(32 位)来表示每个字符。
- 字符范围:
00000000 00000000 00000000 xxxxxxxx(32 位)
小结
- UTF-8:根据字符的 Unicode 码点使用 1 到 4 个字节编码,字节的高位用于标识是否为续字节。
- UTF-16:使用 2 字节表示基本字符,对于超出 BMP 的字符,使用 4 字节(代理对)表示。
- UTF-32:每个字符都使用 4 字节表示,不需要变长或代理对。
每种编码方式都有其应用场景:UTF-8 通常用于存储和传输数据,UTF-16 常用于程序内部处理(如 Java 和 Windows),UTF-32 则在需要直接支持所有字符的情况下使用,但会浪费内存。