先看第一行:
0xxx xxxx
(这里用 x 来代表图里的_
)的 7 个 bit 都可以自由变化,所以0xxx xxxx
可以有 2^7 种取值。0x00 ~ 0x7F
这个范围内有多少种 取值,即 这两个数相减再加 1 ,那么为0x80
,确实也是 2^7 。再看第二行:
110x xxxx
和10xx xxxx
,总共有 11 个 bit 可以变化,所以110x xxxx
和10xx xxxx
可以有 2^11 种取值。0x0080 ~ 0x07FF
这个范围内有多少种 取值,即 这两个数相减再加 1 ,那么为15 * 2^7
2^4 * 2^7
即16 * 2^7
),后者是15 * 2^7
种取值,对不上了。110x xxxx
和10xx xxxx
多出来了一个2^7
的范围,这还刚好可以把 第一行的编码给编进去,这样的话,就刚好一一对应了,但是第一行的编码不是只能用0xxx xxxx
来编码吗?这不就感觉很奇怪了。 1
wudicgi 2022-05-17 22:23:11 +08:00
可能是因为这个,有的字节是不能出现的
https://zh.wikipedia.org/zh-cn/UTF-8 根据这种方式可以处理更大数量的字符。原来的规范允许长达 6 字节的序列,可以覆盖到 31 位(通用字符集原来的极限)。尽管如此,2003 年 11 月 UTF-8 被 RFC 3629 重新规范,只能使用原来 Unicode 定义的区域,U+0000 到 U+10FFFF 。根据这些规范,以下字节值将无法出现在合法 UTF-8 序列中: 编码(二进制) 编码(十六进制) 注释 1100000x C0, C1 过长编码:双字节序列的头字节,但码点 <= 127 1111111x FE, FF 无法达到:7 或 8 字节序列的头字节 111110xx 1111110x F8, F9, FA, FB, FC, FD 被 RFC 3629 规范:5 或 6 字节序列的头字节 11110101 1111011x F5, F6, F7 被 RFC 3629 规范:码点超过 10FFFF 的头字节 |
2
wudicgi 2022-05-17 22:25:33 +08:00
去掉 0xC0, 0xC1
(2^5-2)*(2^6) = 1920 = (0x7FF-0x80)+1 就能对上了 |
3
amiwrong123 OP @wudicgi #2
好像懂了,虽然实际上 110x xxxx 和 10xx xxxx 可以把 0x0000 ~ 0x07FF 都编码进去(而不只是 0x0080 ~ 0x07FF )。 但设计上,不允许让 属于第一行的 0x00 ~ 0x7F 这个范围 的码点,被第二行 编码进去。 这么看的话,第三行也是一样: - 有 16 个自由变化 bit ,所以实际上可以把 0x0000~0xFFFF 都给编码进去的。但设计上,不允许让 0x0000~0x07FF 的码点被编码进第三行。 |
4
az467 2022-05-18 00:07:55 +08:00
主要是为了禁止 overlong encoding ,没必要用 N+M 个 byte 表示 N 个 byte 就能表示的东西。
顺便配合规范,总共就 10FFFF 个码点,不支持 4 bytes 以上的格式了。 |
5
SoloCompany 2022-05-18 00:17:13 +08:00 via iPad 1
因为 utf8 是一个安全的编码,确保在任意地方截断后都能 recover
举一个反例,gb 编码就不是安全的编码,在半字中间阶段会导致所有编码全部错位 更差的例子是 big5 ,允许使用 ascii 字符作为编码的一部份,导致一些 markup 语言(包括 ini )直接出错 |
6
3dwelcome 2022-05-18 00:54:42 +08:00
"因为 utf8 是一个安全的编码,确保在任意地方截断后都能 recover"
感觉这个说法不对,就算把 110x xxxx 和 10xx xxxx 的 2^11 种取值用完,也是可以正常 recover 的。 还是赞同一楼的说法,既然 utf8 映射 unicode 有一定冗余空间,那就没必要全部用完。保留出一些头字节和 BOM ,也是完全没问题的。 |
7
fourthLALA 2022-05-18 01:00:57 +08:00 via iPhone
为啥我完全没理解。。。0x07FF − 0x0080 = 77f ,再加上 1 ,不就是 2^11 次发吗。
|
8
fourthLALA 2022-05-18 01:04:41 +08:00 via iPhone
我傻逼了,请无视我
|