Skip to main content

3. UTF-8 definition (UTF-8定义)

UTF-8由Unicode标准 [UNICODE] 定义。描述和公式也可以在ISO/IEC 10646-1 [ISO.10646] 的附录D中找到。

编码范围

在UTF-8中,U+0000..U+10FFFF范围(UTF-16可访问范围)内的字符使用1到4个八位字节的序列进行编码。

编码规则

单八位字节序列 (1字节)

"序列"中的唯一八位字节将高位位设置为0,其余7位用于编码字符编号。

多八位字节序列 (2-4字节)

在n个八位字节的序列中(n>1):

  • 初始八位字节: n个高位位设置为1,后跟一个设置为0的位。该八位字节的其余位包含要编码的字符编号的位。
  • 后续八位字节: 所有后续八位字节都将高位位设置为1,下一位设置为0,每个八位字节中剩余6位用于包含要编码的字符编号的位。

UTF-8编码表

下表总结了这些不同八位字节类型的格式。字母 x 表示可用于编码字符编号位的位。

字符编号范围 (十六进制)    |    UTF-8八位字节序列 (二进制)
──────────────────────────────────────────────────────────
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

范围说明

范围字节数位数覆盖范围
U+0000 - U+007F17位128个字符 (ASCII)
U+0080 - U+07FF211位1,920个字符
U+0800 - U+FFFF316位61,440个字符
U+10000 - U+10FFFF421位1,048,576个字符

编码过程 (Encoding Process)

将字符编码为UTF-8的步骤如下:

步骤1: 确定所需的八位字节数

从字符编号和上表的第一列确定所需的八位字节数。重要的是要注意,表的行是互斥的,即,只有一种有效的方式来编码给定的字符

步骤2: 准备高位位

按照表的第二列准备八位字节的高位位。

步骤3: 填充字符编号位

从字符编号的位(以二进制表示)填充标记为 x 的位:

  1. 首先将字符编号的最低位放入序列最后一个八位字节的最低位
  2. 然后将字符编号的下一个高位放入该八位字节的下一个高位,依此类推
  3. 当最后一个八位字节的 x 位填充完毕后,移至倒数第二个八位字节
  4. 然后移至前一个八位字节,依此类推,直到所有 x 位都被填充

编码示例

字符: 'A'
Unicode: U+0041 = 0x41 = 65

1. 确定字节数: U+0041在0x00-0x7F范围 → 1字节
2. 模板: 0xxxxxxx
3. 填充: 0x41 = 0100 0001 → 01000001
结果: 0x41

────────────────────────────────────────

字符: '你'
Unicode: U+4F60 = 0x4F60 = 20320

1. 确定字节数: U+4F60在0x800-0xFFFF范围 → 3字节
2. 模板: 1110xxxx 10xxxxxx 10xxxxxx
3. 0x4F60二进制: 0100 1111 0110 0000
4. 填充:
- 低6位 (100000) → 10100000 = 0xA0
- 中6位 (111101) → 10111101 = 0xBD
- 高4位 (0100) → 11100100 = 0xE4
结果: 0xE4 0xBD 0xA0

禁止编码代理对

UTF-8的定义禁止编码U+D800和U+DFFF之间的字符编号,这些编号保留用于UTF-16编码形式(作为代理对)并且不直接表示字符。

从UTF-16数据编码为UTF-8时,必须首先解码UTF-16数据以获得字符编号,然后按上述方式编码为UTF-8。

UTF-8 vs CESU-8

这与CESU-8 [CESU-8] 形成对比,后者是一种类似UTF-8的编码,但不用于互联网。CESU-8的操作类似于UTF-8,但编码UTF-16码值(16位量)而不是字符编号(码点)。这对于0xFFFF以上的字符编号会导致不同的结果;这些字符的CESU-8编码不是有效的UTF-8。

解码过程 (Decoding Process)

解码UTF-8字符的步骤如下:

步骤1: 初始化

初始化一个所有位都设置为0的二进制数。可能需要最多21位。

步骤2: 确定哪些位编码字符编号

从序列中的八位字节数和上表的第二列确定哪些位编码字符编号(标记为 x 的位)。

步骤3: 分配位

将序列中的位分配给二进制数:

  1. 首先从序列的最后一个八位字节的低位开始
  2. 向左进行,直到没有 x 位为止
  3. 现在二进制数等于字符编号

解码示例

字节序列: 0xE4 0xBD 0xA0

1. 检测模式: 1110xxxx → 3字节序列
2. 提取位:
0xE4 = 11100100 → 提取 0100
0xBD = 10111101 → 提取 111101
0xA0 = 10100000 → 提取 100000
3. 组合: 0100 111101 100000 = 0100111101100000
4. 转换: 0x4F60 = U+4F60 = '你'

⚠️ 安全要求

解码算法的实现必须 (MUST) 防止解码无效序列。

危险示例

无效序列1: C0 80
天真的实现可能解码为: U+0000
问题: 这是过长编码(应该是 0x00)

无效序列2: ED A1 8C ED BE B4
天真的实现可能解码为: U+233B4
问题: 这是代理对的编码(UTF-8中禁止)

解码无效序列可能会产生安全后果或导致其他问题。参见第10章安全考虑。

关键要点总结

特性说明
唯一编码每个字符只有一种有效的UTF-8编码
范围限制仅U+0000到U+10FFFF
禁止代理对U+D800-U+DFFF不能编码
禁止过长编码必须使用最短的可能序列
安全性必须验证并拒绝无效序列

相关链接