首页 > 代码库 > 刨根究底字符编码之十二——UTF-8究竟是怎么编码的
刨根究底字符编码之十二——UTF-8究竟是怎么编码的
UTF-8究竟是怎么编码的
1.
UTF-8编码是Unicode字符集的一种编码方式(CEF),其特点是使用变长字节数(即变长码元序列、变宽码元序列)来编码。一般是1到4个字节,当然,也可以更长。
为什么要变长呢?这可以理解为按需分配,比如一个字节足以容纳所有的ASCII码字符,那何必补一堆0用更多的字节来存储呢?
实际上变长编码有其优势也有其劣势,优势是节省空间、自动纠错性能好、利于传输、扩展性强,劣势是不利于程序内部处理,比如正则表达式检索;而UTF-32这样等长码元序列(即等宽码元序列)的编码方式就比较适合程序处理,当然,缺点是比较耗费存储空间。
2.
那UTF-8究竟是怎么编码的呢?也就是说其编码算法是什么?
UTF-8编码最短的为一个字节、最长的目前为四个字节,从首字节就可以判断一个UTF-8编码有几个字节:
如果首字节以0开头,肯定是单字节编码(即单个单字节码元);
如果以110开头,肯定是双字节编码(即由两个单字节码元所组成的双码元序列);
如果是1110开头,肯定是三字节编码(即由三个单字节码元所组成的三码元序列),以此类推。
另外,UTF-8编码中,除了单字节编码外,由多个单字节码元所组成的多字节编码其首字节以外的后续字节均以10开头(以区别于单字节编码以及多字节编码的首字节)。
(笨笨阿林原创文章,转载请注明出处)
3.
所以,1~4字节的UTF-8编码看起来分别是这样的:
单字节可编码的Unicode码点值范围:0x0000~0x007F(0~127)
双字节可编码的Unicode码点值范围:0x0080~0x07FF(128~2047)
三字节可编码的Unicode码点值范围:0x0800~0xFFFF(2048~65535)
四字节可编码的Unicode码点值范围:0x10000~0x1FFFFF(65536~2097151)
(笨笨阿林原创文章,转载请注明出处)
4.
127、2047、65535、2097151这几个临界值怎么来的呢?
因为UTF-8编码中的每个字节中都含有起到标识之用的0、110、1110以及10之一,所以1~4个字节的UTF-8编码其有效位数分别为8-1=7位(2^7-1=127)、16-5=11位(2^11-1=2047)、24-8=16位(2^16-1=65535)、32-11=21位(2^21-1=2097151),如下表:
注:上图中的Unicode range即Unicode码点值范围(也就是Unicode码点编号范围),Hex为16进制,Binary为二进制;Encoded bytes即UTF-8编码中各字节的编码方式(即编码算法),其中,x代表Unicode二进制码点值的低8位、y代表两字节码点值的高8位及三字节码点值的中8位、z代表三字节码点值的高8位。
5.
由于ASCII字符的UTF-8编码使用单字节,而且和ASCII编码一模一样,这样所有原先使用ASCII编码的文档就可以直接解码了,无需进行任何转换,实现了完全兼容。考虑到计算机世界中英文文档的数量之多,这一点意义重大。
而对于其他非ASCII字符,则使用2~4个字节的编码来表示。其中,首字节中前置的1的个数代表该字符编码的字节数(110代表两个字节、1110代表三个字节,以此类推),非首字节之外的剩余字节的高2位始终是10,这样就不会与ASCII字符编码以及非ASCII字符的首字节编码相冲突。
例如,假设某个字符的首字节是1110yyyy,前置有三个1,说明该字符编码总共有三个字节,必须和后面两个以10开头的字节结合才能正确解码该字符。
6.
由此可知,UTF-8编码设计得非常精巧,虽说不上完美无缺,但若与后文将要介绍的UTF-16、UTF-32以及前文介绍过的那些ANSI编码相比较,对于其精巧设计将体会得更为深切透彻。因此,UTF-8越来越得到全球一致认可,大有一统字符编码之势,也就顺理成章了。
(笨笨阿林原创文章,转载请注明出处)
(未完待续)
本系列文章上一篇为:刨根究底字符编码之十一——UTF-8编码方式与字节序标记
【预告:本系列文章下一篇将重点介绍UTF-16编码,敬请关注!】
刨根究底字符编码之十二——UTF-8究竟是怎么编码的