关于unicode字符及其utf8二进制表示

Regarding unicode characters and their utf8 binary representation

出于好奇,我想知道为什么例如一个字符"?"代码点322在十进制197:130中有11000101:10000010UTF8二进制表示,在十进制1:66中没有实际的二进制表示00000001:01000010


UTF-8将U+0000..U+007F范围内的Unicode码位编码为单字节。代码点在U+0080..U+07FF范围内使用2个字节,代码点在U+0800..U+FFFF范围内使用3个字节,代码点在U+10000..U+10FFFF范围内使用4个字节。

当码位需要两个字节时,第一个字节以位模式110开始;其余5位是Unicode码位的高阶5位。延续字节以位模式10开头;其余6位是Unicode码位的低阶6位。

你在看?带粗线的拉丁文小写字母L(十进制322)。代表十六进制142的位模式是:

1
00000001 01000010

使用以冒号标记的utf-8子字段分组,即:

1
00000:001 01:000010

所以utf-8代码是:

1
2
3
4
110:00101 10:000010
11000101  10000010
0xC5      0x82
197       130

同样的基本思想也适用于3字节和4字节的编码——每延续字节切掉6位,并将前导位与适当的标记位结合起来(3字节为1110,4字节为11110——前导1位与完整字符中的字节一样多)。现在还有很多其他的规则对你来说并不重要。例如,您从不使用UTF-8(或UTF-32)编码UTF-16高代理(U+D800..U+DBFF)或低代理(U+DC00..UDFFF)。您从不对非最小序列进行编码(因此,尽管可以使用字节0xC0 0x80对U+0000进行编码,但这是无效的)。这些规则的一个结果是,字节0xc0和0xc1在UTF-8中永远无效(两者都不是0xf5..0xff)。


UTF8是为与7位ASCII兼容而设计的。

为了实现这一点,使用utf8编码字节序列中最重要的字节位来表示一个字节是否是多字节编码码点的一部分。如果设置了MSB,则字节是2个或多个字节序列的一部分,这些字节对单个代码点进行编码。如果未设置msb,则字节对0到127范围内的代码点进行编码。

因此,在utf8中,字节序列[1][66]分别代表两个代码点1和66,因为没有在任一字节中设置msb(=0)。

此外,代码点322必须使用字节序列进行编码,其中每个字节中都设置了msb(=1)。

utf8编码的精确细节要复杂得多,但是有很多资源涉及到这些细节。