首页 > 解决方案 > UTF-8编码为什么要前缀10?

问题描述

据我所知,UTF-8 是一种可变长度编码,即一个字符可以表示为 1 个字节、2 个字节、3 个字节或 4 个字节。

例如,Unicode 字符 U+00A9 = 10101001 在 UTF-8 中编码为

110 00010 10 101001,即0xC2 0xA9

第一个字节中的前缀 110 表示该字符以两个字节存储(因为我在前缀 110 中数了两个 1 直到零)。

以下字节中的前缀以 10 开头

一个 4 字节的 UTF-8 编码看起来像

11110 xxx 10 xxxxxx 10 xxxxxx 10 xxxxxx

前缀 11110(四个一和零)表示四个字节,依此类推。

现在我的问题:

为什么在后面的字节中使用前缀 10?这样的前缀有什么好处?如果我写以下字节中没有 10 前缀,我可以使用 3*2=6 位以上:

1111 0000 xxxxxxxx xxxxxxxx xxxxxxxx

标签: unicodeencodingutf-8character

解决方案


历史上,有很多关于 UTF-8 编码的提议。其中一个在以下字节中不使用前缀,另一个名为FSS-UTF的使用前缀1

Number    First       Last
of bytes  code point  code point
1         U+0000      U+007F       0xxxxxxx
2         U+0080      U+07FF       110xxxxx 10xxxxxx
3         U+0800      U+FFFF       1110xxxx 10xxxxxx 10xxxxxx
4         U+10000     U+1FFFFF     11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5         U+200000    U+3FFFFFF    111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6         U+4000000   U+7FFFFFFF   1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

10然而最终选择了使用前缀的新编码

贝尔实验室 Plan 9 操作系统组的 Ken Thompson 进行了修改,使其位效率低于之前的提议,但至关重要的是,它可以自我同步,让阅读器从任何地方开始并立即检测字节序列边界。

https://en.wikipedia.org/wiki/UTF-8#History

正如其他人提到的,新编码最明显的优势是自同步。它允许读者轻松找到字符边界,因此可以快速跳过任何丢弃的字节,并且在给定字符串中的任何字节索引的情况下也可以立即找到当前/上一个/下一个字符。如果索引字节以 10 开头,那么只是一个中间字节,只需向后或向前查找周围字符的开头;否则,如果它以 0 或 11 开头,则它是字节序列的开头

该属性非常重要,因为在没有像Shift-JIS这样的自同步的糟糕设计的编码中,阅读器必须维护一个字符偏移表,否则它必须从头开始重新解析数组以编辑字符串。在用于日语的 DOS/V 中(使用 Shift-JIS)可能是由于未使用该表的内存量有限,因此每次按下Backspace操作系统时都需要从头开始重复以了解删除了哪个字符。无法像 UTF-8 一样获得前一个字符的长度

UTF-8 的前缀特性还允许旧的 C 字符串搜索函数无需任何修改即可工作,因为搜索字符串的字节序列永远不会出现在另一个有效的 UTF-8 字节序列的中间。在 Shift-JIS 或其他非自同步编码中,您需要专门的搜索功能,因为起始字节可以是另一个字符的中间字节

UTF-16 也有上述的一些优点

由于高代理项 (0xD800–0xDBFF)、低代理项 (0xDC00–0xDFFF) 和有效 BMP 字符 (0x0000–0xD7FF, 0xE000–0xFFFF) 的范围是不相交的,因此代理项不可能匹配 BMP 字符,或者让两个相邻的代码单元看起来像一个合法的代理对。这大大简化了搜索。这也意味着 UTF-16 在 16 位字上是自同步的:一个代码单元是否开始一个字符可以在不检查早期代码单元的情况下确定(即代码单元的类型可以通过它所在的值的范围来确定)下降)。UTF-8 具有这些优点,

https://en.wikipedia.org/wiki/UTF-16#Description


推荐阅读