UTF-8

柔情只为你懂 2022-05-30 05:45 379阅读 0赞

文章假设你已经熟知计算机的基本单位( 1 字节 = 8 位二进制 = 2 位十六进制 ),且对 Unicode 有清楚的理解。

描述

网络上已经有很多关于 UTF-8 的描述版本了,这里尝试从另一个角度对 UTF-8 进行描述。

Unicode 使用「 1个16进制的字节+2个16进制字节 」(从 000010 FFFF )的编码方式与全球所有语言的字符进行对应,但这会大大提高浪费计算机储存空间的概率。比如很多英文字母的 Unicode 码是 00xx ,单单一个字母就浪费了2个单位( 00 )的储存位,这样一篇英文文章至少会浪费一半的储存空间。为了合理利用计算储存空间,UTF-8 应运而生。
之前的计算机只能死脑筋地认为 i 个字节表示一个字符,这会导致新字符的兼容性问题(例如后来加入新的字符需要 i+1 个字节表示)以及前文提及的储存空间浪费问题。
UTF-8 通过一定的规则,使得字符转译生成的编码的长度不再固定。除了本身的 Unicode 编码之外,每个字符还会嵌入自己的编码长度信息。UTF-8 的引入增加了字符的编码长度的可拓展性,允许将来新的字符的引入,也同时避免了储存空间的浪费。

编码规则

UTF-8 的编码规则只有2条:

  1. 对于单字节的 UTF-8 编码(二进制),字节的第 1 位设为 0,后面 7 位为这个字符的 Unicode 码。因此对于英文字母,UTF-8 编码和 ASCII 码是相同的。
  2. 对于 n 字节(n > 1)的 UTF-8 编码(二进制),第 1 个字节(二进制)的前 n 位都设为1,第 n+1 位设为 0,后面字节的前 2 位一律设为10。剩下的没有提及的二进制位,全部为这个字符的 Unicode 码。

上面的规则描述可用下面的表格来诠释(字母 x 表示可填编码的位):




































字节数 UTF-8 编码结构(二进制) 可填写的编码范围(二进制)
1 0xxxxxxx (0)000 0000 ~ (0)111 1111
2 110xxxxx 10xxxxxx (0)000 0000 0000 ~ (0)111 1111 1111
3 1110xxxx 10xxxxxx 10xxxxxx 0000 0000 0000 0000 ~ 1111 1111 1111 1111
4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx (000)0 0000 0000 0000 0000 0000 ~ (000)1 1111 1111 1111 1111 1111

这样的规则解决了2个问题:计算机如何识别字节长度不一的字符、UTF-8 如何与 Unicode 一一对应

计算机如何识别字节长度不一的字符

UTF-8 是允许有不同字节数的字符存在的,那么计算机编译器是如何从类似111001101011010110110111111010011001100010010100 这样的0/1编码中识别出一个个字符的?
计算机编译器在编译第 1 个字节时,判断这个字节的第 1 位是 0 还是 1 : 若是 0,则这个字节就表示一个字符;若是 1 ,则计算从这个 1 开始(包含)到 0 结束,有 n 个 1,那么从这个字节开始(包含)的 n 个字节就表示一个字符。
当识别出第 1 个字符后,以此类推,继而判断第 2 个字符的字节数,识别出第 2 个字符;再识别第 3 个字符……直到最后一个字符,这样就实现了所有字符的识别(解码)过程。
比如上面的 1110010110111100100000000101000001100001011100100111010001111001 可以分割为6个字符:
| 11100101 10111100 10000000 | 01010000 | 01100001 | 01110010 | 01110100 | 01111001 |

UTF-8 如何与 Unicode 一一对应

根据 UTF-8 的规则,字符在有限的字节编码中,抛去标示声明字节的编码位,剩下的就是可编写的——见上面表格“UTF-8 编码结构(二进制)”中字母“x”表示的二进制位,就是留给 Unicode 码填入的,这就实现 UTF-8 与 Unicode 的一一对应了。
但是这些可编写的二进制位的编码范围是有限的,如 1 个字节的 UTF-8 编码可编写 27 2 7 (即128) 个 Unicode 码,即可编写从 0000007F 的 Unicode 码。
下表总结了不同字节数 UTF-8 码可编码的 Unicode 范围(字母 x 表示可用编码的位):




































UTF-8 编码结构(二进制) 可编写 Unicode 位数(二进制) 可编写 Unicode 编码范围(十六进制)
0xxxxxxx 0~7位 0000 0000 ~ 0000 007F
110xxxxx 10xxxxxx 8~11位 0000 0080 ~ 0000 07FF
1110xxxx 10xxxxxx 10xxxxxx 12~16位 0000 0800 ~ 0000 FFFF
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 17~21位 0001 0000 ~ 0010 FFFF

以中文字符 为例,将其 Unicode 码 6D77 编译为 UTF-8 码步骤:

  1. 将十六进制 6D77 转换为二进制 1101101 01110111,位数是15位;
  2. 根据规则,3 个字节的 UTF-8 码可编译 12~16 位 Unicode 码(见上表),最适合编译当前字符;
  3. 1101101 01110111 依次填入 3 字节的 UTF-8 码可编辑位(多余的最高位补上 0 ),得到 11100110 10110101 10110111 ,这个就是 UTF-8 码了;
  4. 如果愿意,可以将其转换为 16 进制 E6 B5 B7
    值得注意的是,虽然超过 3 个字节的 UTF-8 码的可编写位数也能够填入 15 位的 1101101 01110111、多余的高位补上 0 ,但这样做编译器不会同等识别出来。
    笔者猜测是因为这样不利于节约储存空间,且已经有最优解——采用 3 个字节的 UTF-8 码编译,所以 UTF-8 干脆不做重复的字符编码了。因此在 UTF-8 中,推荐以最短字节数表示字符,不允许冗余的字节。这也是上面表格中“可编写 Unicode 编码范围(十六进制)”的起点不和 UTF-8 可编辑位范围一致的原因( 1 字节除外)。
    从这点来看,UTF-8 的变长字节优势凸显,但也存在部分编码留白的现象。

参考:字符编码详解

发表评论

表情:
评论列表 (有 0 条评论,379人围观)

还没有评论,来说两句吧...

相关阅读

    相关 UTF-8

    文章假设你已经熟知计算机的基本单位( 1 `字节` = 8 `位二进制` = 2 `位十六进制` ),且对 Unicode 有清楚的理解。 描述 > 网络上已经有很多关

    相关 UTF-8

    \\\UTF-8是一种变长字节编码方式。对于某一个字符的UTF-8编码,如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数