写给应用开发的 Android Framework 教程是一个系列教程,目前已更新以下内容:
-
系统开发基础
-
AOSP 上手指南
-
学穿 Binder 系列
-
HAL 与硬件服务
Unicode 是一个字符集,其中包含了一百多万个字符。每一个字符都分配了一个唯一的 ID,这个 ID 学名叫做 Code Point。Code Point 的范围为 0x0000-0x10FFFF。规定使用 "u+十六进制数字" 来表示 Code Point,例如 "u+4E2D" 表示汉字中的 "中" 字的 Code Point。
UTF-32
信息从一种形式或格式转换为另一种形式的过程称之为编码。
接下来的问题就是如何对 Code Point 进行编码使其便于计算机存储和处理。
最简单的办法就是直接存储 Code Point 的二进制值。Code Point 的最大值为 0x10FFFF,最少需要 3 个字节才能存储。考虑到后续可能的变动,我们干脆就使用 4 个字节来存储。
上面的过程就是最简单的编码方式(不变),称之为 UTF-32。编码后的字节序列称之为 Code Unit。
具体的编码规则如下:
u+0000 ~ u+10FFFF: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
UTF-16
UTF-32 对于 Code Point 较小的字符,也需要四个四节来存储。这样虽然简单,但是浪费了空间。
容易想到 Code Point 小点的字符用两个字符表示,大点的字符用四个字符表示,具体规则如下:
- 对于 Code Point 小于 0x10000 的字符,使用2个字节存储,并且是直接存储Unicode 码。
- 对于 Code Point 在 Ox10000 和 Ox10FFFF 之间的字符,使用4个字节存储,这4个字节分成前后两部分,每个部分各两个字节,其中,前面两个字节的前6位二进制固定为110110,后面两个字节的前6位二进制固定为110111,前后部分各剩余10位二进制表示符号的 Unicode 码减去Ox10000的结果
u+ 0000 ~ u+ FFFF: xxxxxxxx xxxxxxxx
u+10000 ~ u+10FFFF: 110110xx xxxxxxxx 110111xx xxxxxxxx (x 位表示 Code Point 减去Ox10000的结果)
上面的编码方式,称之为 UTF-16。
UTF-8
相同的思路,我们可以将 Code Point 区间进一步细分:
U+ 0000 ~ U+ 007F: 0XXXXXXX
U+ 0080 ~ U+ 07FF: 110XXXXX 10XXXXXX
U+ 0800 ~ U+ FFFF: 1110XXXX 10XXXXXX 10XXXXXX
U+10000 ~ U+10FFFF: 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
根据上表中的编码规则,「知」字的码位 U+77E5 属于第三行的范围:
7 7 E 5
0111 0111 1110 0101 二进制的77E5
--------------------------
0111 011111 100101 二进制的77E5
1110XXXX 10XXXXXX 10XXXXXX 模版(上表第三行)
11100111 10011111 10100101 代入模版
E 7 9 F A 5
这就是将 U+77E5 编码为字节序列 E79FA5 的过程。以上的编码方式称之为 UTF-8
总结
- Unicode是「字符集」
- UTF-8、UTF-16、UTF-32等是「编码规则」
其中:
- 字符集:为每一个「字符」分配一个唯一的 ID (Code Point)
- 编码规则:将「Code Point」转换为字节序列的规则,转换后的字节序列称之为 「Code unit」。
广义的 Unicode 是一个标准,定义了一个字符集以及一系列的编码规则,即 Unicode字符集和 UTF-8、UTF-16、UTF-32 等编码规则。通过这些编码规则一个码位(Code Point)就会对应一个编码,这个编码就称为 Code Unit。