python 之 utf-8编码的秘密

时间:2023-01-05 09:42:17

python3的默认编码方案是utf-8编码,看了些资料,来做总结。


要说utf-8,就要说说unicode,要说unicode,就要说ASCII,我们还是慢慢来。


1.ASCII

      ASCII编码最初是由老美搞出来的,满足了英文在计算机中的的表达和存储。开始呢,ASCII使用一个字节的后7位来进行编码。

每位有0,1 两种状态,那么就有2^7个数(十进制从0~127)来代表128个不同的字符。后来人们又对ASCII码进行了扩展,把最高位也用上了,那么就又多了128个可编码的空间。


     可是,全世界难道就只有老美用计算机吗?中文,韩文,日文,阿拉伯文.....在计算机中怎么表示呢?

       于是各国开始搞自己的一套编码方案,比如我国常见的GBK系列编码,基本解决看了中文编码的问题。

     随着网络的日益发达,人们的交流不限于自己的国家,还可以通过网络与国外交流。但是碎片化的文字编码阻碍了不同国家文字的传播,乱码时常发生。

   于是,伟大的创想Unicode诞生了。


2.Unicode

       “Unicode(万国码、单一码)是一种在计算机上使用的字符编码。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。1990年开始研发,1994年正式公布”

          但是,unicode并没有被广泛使用,其中一个很重要的原因是:unicode如何编码?如果统一用2个字节编码,那么ASCII用户就不高兴了,因为原先的ABC只占3个字节,采用unicode就会翻倍为6个字节,但是不采用多为字节编码,那么如何容纳世界各国的语言呢?万国码的创想又怎么能够实现?


        为了解决这个问题,utf-8    utf-16    utf-32相继诞生

3.utf-8

        utf-8机智地使用了变长编码方式。具体如下:


NULL Unicode码范围 utf-8编码填充模板
一区 0000 0000~0000 007F 0xxxxxxx
二区 0000 0080~0000 07FF 110xxxxx 10xxxxxx
三区 0000 0800~0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
四区 0001 0000~0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx



可以看出:一区的字符都是采用一个字节编码,而一区的字符就是原来的ASCII字符,所以utf-8是兼容ASCII的,因此一个纯粹的ASCII码文件也能被考虑为一个UTF-8 文件, 而且一个碰巧只使用ASCII码字符的 UTF-8 文件和拥有同样字符的ASCII码文件是相同的。

再来看三区,这个区集中了大部分的中文编码。

根据Unicode的汉字编码查询表(http://bianma.supfree.net/sos.asp?id=14)可知,汉字”中“的Unicode编码为:0X4E2D,而 0X4E2D   在  0000 0800~0000 FFFF这个范围内,所以,将”中“的Unicode编码的二进制

100111000101101   从低位到高位 从后往前填充 到 对应utf-8模板  1110xxxx 10xxxxxx 10xxxxxx   中,取代里面的  'x'  ,填充后若有多余的 ‘x’  用 0 取代之,得到的二进制数据   11100100 10111000 10101101 就是"中"的utf-8编码,用16进制表示就是:

\xe4\xb8\xad


也就是说:unicode提供了各种字符的编码值,也可以叫做代号,一个字符有一个独一无二的值,这个值正是unicode确定的。
而utf-8则是提供了字符在内存中的编码和解码方案。


utf-8引擎如何解码?

这是我一直在想的问题,下面是我的猜测。如有不对之处,敬请批评指正。

ASCII码字符都只占一个字节,所以解码ASCII很方便,只需要读取一个字节的数据,翻译为字符,再读取一个字节的数据,翻译为字符。。。。。

可是,utf-8是变长编码,它怎么知道要下一个字符需要读取几个字节来翻译为一个字符呢?

python 之 utf-8编码的秘密

我们可以把红色框框(也就是一个字符utf-8编码的第一个字节)看作”组长”,后面的连续的字节看作“小组普通成员”。那个,这个小组一共有多少人,都包含在组长的信息里面。

一区的组长的最高位是0,就暗含信息:我这个组只有我一个人,那么utf-8引擎在解码的时候就只去读这一个字节,完成翻译。

二区的组长最高为位有2个1,暗含信息:我这个组有2个人,那么utf-8引擎在解码的时候就只去读这2个字节,完成翻译。

三区的组长最高为位有3个1,暗含信息:我这个组有3个人,那么utf-8引擎在解码的时候就只去读这3个字节,完成翻译。

同时,为了防止数据损坏而造成数据丢失,每个普通成员字节的前2位都是10,来标识自己是成员身份。