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+007F | 1 | 7位 | 128个字符 (ASCII) |
| U+0080 - U+07FF | 2 | 11位 | 1,920个字符 |
| U+0800 - U+FFFF | 3 | 16位 | 61,440个字符 |
| U+10000 - U+10FFFF | 4 | 21位 | 1,048,576个字符 |
编码过程 (Encoding Process)
将字符编码为UTF-8的步骤如下:
步骤1: 确定所需的八位字节数
从字符编号和上表的第一列确定所需的八位字节数。重要的是要注意,表的行是互斥的,即,只有一种有效的方式来编码给定的字符。
步骤2: 准备高位位
按照表的第二列准备八位字节的高位位。
步骤3: 填充字符编号位
从字符编号的位(以二进制表示)填充标记为 x 的位:
- 首先将字符编号的最低位放入序列最后一个八位字节的最低位
- 然后将字符编号的下一个高位放入该八位字节的下一个高位,依此类推
- 当最后一个八位字节的
x位填充完毕后,移至倒数第二个八位字节 - 然后移至前一个八位字节,依此类推,直到所有
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: 分配位
将序列中的位分配给二进制数:
- 首先从序列的最后一个八位字节的低位开始
- 向左进行,直到没有
x位为止 - 现在二进制数等于字符编号
解码示例
字节序列: 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不能编码 |
| 禁止过长编码 | 必须使用最短的可能序列 |
| 安全性 | 必须验证并拒绝无效序列 |