• 信息论进阶:聊聊UTF-8的信息熵

UTF-8都知道是啥,所有人都在用它来存储和传输文本。鄙人闲来无事研究了一下utf8的规格,发现它并没有想象中的那样完美。

问题起源于StackOverflow上的一位网友提问:

这难道是UTF-8字符编码的设计缺陷?_字符串

地址:https://stackoverflow.com/questions/53009692/utf-8-encoding-why-prefix-10

网友提到,utf8本是一个可变长度字符编码,这意味着utf8的设计目标是为了节省流量,给使用频率高的字符以短字节,给“冷门”的字符以长字节,就像哈夫曼编码一样。但后来我发现了一个惊人的事实:

  • UTF-8并不遵循哈夫曼编码(Huffman Coding)

当然这是废话,他俩本来就是不同的编码,但是UTF-8并没有理想中那么“紧凑(compact)”,存在一些无用信息。比如一个4字节的utf8编码后的字符表示为:

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

这样设计很明显:utf8是一种无前缀编码,解码时不会混淆。最开始的11110暗示了该字符有4个字节(4个1),后面每个字节前的10代表这个字节是该字符剩下的字节,xxx就代表有效信息。现在网友的问题就是,utf8所有剩余字节的前缀10都是多余的!

这个质疑很自信,首字节的前缀已经暗示了总字节数,不再需要后续字节了。从信息论的角度,一个“意思”用不同的方式暗示2遍是在浪费信息。所以上面这个字符可以写成:

11110000 xxxxxxxx xxxxxxxx xxxxxxxx

这样子1个字符就节省了3*2=6个bit,如果这样设计utf8的话,互联网效率将大大提升。

提不提升先放一边,因为很快有stack大神回复了:

这难道是UTF-8字符编码的设计缺陷?_数据_02

图中2个大神分别陈述了utf8采用这种“多前缀”的编码方案的2点理由,我来简单翻译一下:

  • 理由1:“多前缀”有利于网络传输时同步

Joachim Sauer的意思是utf-8这样设计可以避免网络传输过程中掉帧,或者其他情况下数据发生缺失。这个想法是基于一个重要事实,即扫描utf8每一个字节的时候可以不依赖于其他字节来判断它的类型。这就是:

  • UTF-8和Huffman的本质区别

Huffman编码后的数据必须从左向右扫描才能识别每一个字符,因为每一个字符的前缀暗示了该字符的长度,所以依次排列的每一个字符都要依赖前一个邻居字符来标明自己的位置,以此递归。

而UTF-8可以从右向左扫描,甚至从中间开始!这是因为utf8每个字节都有自己的前缀,无需依赖其他的字节。这样的话,网络传输一个字符串的时候如果发生掉帧,接收方也可以通过前缀来自动同步,不用将整个字符串重传一遍。但我想说的是:

  • 网络传输不需要UTF-8

可能有人要反驳我,先别急,我来给你反正:如果说UTF-8有用的话,那就是说我们一直在利用utf8的前缀来保障网络传输的同步,从而提高了效率,但事实上,几乎所有的网络数据在解析出其中的字符串之前都至少经过网络层或者应用层的数据完整性校验,比如http的校验,在校验阶段就能保证所传输的所有数据的完整性,在此之后解析出的字符串自然是完整的,这样UTF-8前缀提供的优点现在变得一无是处。

既然utf8的前缀机制在网络传输中根本没用到,那这种前缀显然就是资源浪费了,正如图一中knowledge所质疑的。解决方案也显而易见,就是换一种编码方案,比如Huffman编码。

UTF-8只是不适用于网络传输,但它本身是一个优良的设计,正如图二中Remy Lebeau提出的理由二一样。

  • 理由2:UTF-8提供了更好的数据索引

把字符串想象成一个数据库。

都知道索引是一种避免数据库全盘扫描的好办法,那么Huffman编码只提供了1种索引:通过每个字符的前缀来跳跃式地检索数据。而UTF-8显然不止一种索引,除了像Huffman那样索引,还可以逆向索引,甚至可以从中间开始搜索。

综上所述,编码的本质是为数据的存储和传输服务。存储的时候使用UTF-8这种“多索引”式的编码方式,牺牲一点存储空间来换取检索的效率非常OK,但传输的时候最好使用Huffman这种“单索引”式的编码来提高传输效率。然而如今的HTTP仍然在滥用UTF-8,不知道未来能否改变?

(玩)

这难道是UTF-8字符编码的设计缺陷?_字符串_03

日记


        上个月经历了最幸运的一天:早上打开自己的电脑,打开浏览器后2分钟屏幕开始撕裂,10秒后黑屏,到维修店花了300对MacBook Pro拆机清理后正常使用。

        幸运之处有三,其一是本来预感要更换¥4000左右的腐蚀主板,最后省去了这笔钱;其二是之后开始使用公司16G的Win10台式机敲代码,体验非常好;其三是黑屏正好在早上,没丢失任何未同步到云端的数据。