Unicode与UTF-8
计算机编码发展的历史
关于计算机系统中编码的历史(例如ASCII、GBK这些编码等等)就不介绍了,如果感兴趣可以看看知乎上面的这个回答。
Unicode字符集
Unicode(Universal Multiple-Octet Coded Character Set)是由ISO提出的,这是一种旨在包含目前世界上所有文化、所有字母的字符编码表,其目的是世界上任意一个字符都可以在该表中找到其所对应的编码值。Unicode字符集兼容ASCII码中的 0 ~ 127 位字符,对于这些字符Unicode会将其ASCII码值放在低位,高位全部置为零。
Unicode字符平面映射把Unicode分为17个平面(Plane),每个平面拥有 2 ^ 16 = 65536
个代码点,即每个平面可以表示65536个字符。这17个平面的范围如下表:
平面 | 编码取值范围 |
---|---|
0号平面 | U+0000 - U+FFFF |
1号平面 | U+10000 - U+1FFFF |
2号平面 | U+20000 - U+2FFFF |
3号平面 | U+30000 - U+3FFFF |
4号平面 - 13号平面 | U+40000 - U+DFFFF |
14号平面 | U+E0000 - U+EFFFF |
15号平面 | U+F0000 - U+FFFFF |
16号平面 | U+100000 - U+10FFFF |
作为使用者,我们并不需要了解Unicode是如何设计并对字符进行分类的,我们只需要知道在Unicode中一个字符对应了一个唯一的编码就可以了,这个唯一编码叫做code point
,其实就是该字符在编码表中的位置下标。
utf-8编码
utf-8是Unicode的一种变长度的编码表达方式,Unicode字符集中有相当多的字符其编码高位都是零,这浪费了很多的空间。为了节省空间,可以使用utf-8编码方式对Unicode做进一步的编码注1。相较于Unicode,使用utf-8编码可以显著的减少字符的空间占用。
utf-8对Unicode编码值小于U+FFFF的字符编码效率较高,而对于高于U+FFFF的字符值使用utf-16编码可能是个更好的选择,好在我们常用的字符其编码值基本上都不会超过U+FFFF,所以一般来说utf-8编码方式已经足够满足我们的需求。不过事实上,假设不使用utf-8或者utf-16等编码方式,而是直接使用Unicode编码加上使用数据压缩算法(例如DEFLATE)的方式,也能得到较好的空间节省效果。
我们已经知道了引入utf-8编码机制的目的是为了减少空间的占用,下面我们就详细了解一下utf-8的编码方式。如下是一个utf-8编码与Unicode编码的关系表
位数 | Unicode范围 | 字节数 | 字节1 | 字节2 | 字节3 | 字节4 |
---|---|---|---|---|---|---|
7 | U+0000 - U+007F | 1 | 0xxxxxxx | |||
11 | U+0080 - U+07FF | 2 | 110xxxxx | 10xxxxxx | ||
16 | U+0800 - U+FFFF | 3 | 1110xxxx | 10xxxxxx | 10xxxxxx | |
21 | U+10000 - U+1FFFFF | 4 | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
上面只列举了utf-8编码在4个字节以内的编码方式,再多的因为很少使用没有列举出来。上表中的 x
代表了utf-8编码中的编码值,可以根据字符计算得到。
根据上表我们可以得到utf-8编码四种情况:
- 第一个bit为0,则说明这个字符只占用一个字节,字符的值为后7个bit
- 前三个bit为110,则说明这个字符占用两个字节,字符的值为第一个字节的后5个bit加上第二个字节的后6个bit
- 前四个bit为1110,该字符占用三个字节,字符的值为 字节一[4:] + 字节二[2:] + 字节三[2:]
- 前五个bit为11110,该字符占用四个字节,字符的值为 字节一[5:] + 字节二[2:] + 字节三[2:] + 字节四[2:]
下面我们看一个实际的utf-8和unicode相互转化的例子:
1 | package main |
总结
utf-8作为现在最广泛使用的编码方式,了解一下其工作原理还是有必要的。utf-8离不开unicode,utf-8编码出现的目的是为对unicode的编码值进行压缩,这才是utf-8编码的最核心意义。
注
- 这里有点绕,Unicode和utf-8都是编码方式,我们可以这样对它们作区分:
- Unicode是一种表驱动的编码方式,即编码值是通过查表的方式获得的
- utf-8是一种通过计算而编码的方式,我们可以通过计算来实现一个字符的utf-8编码与Unicode编码的相互转化