[Python学习日记-22] Python 中的字符编码(下)
简介
在[Python学习日记-21] Python 中的字符编码(上)中我们讲了字符编码中的 ASCII 码和 GB2312/GBK,本片我们来讲述当时犹如雨后春笋般的编码战国时代和万国码时代,以及 Python 在这时代背景下的一些特性
编码的战国时代
之前我们讲了 GB2312/GBK 编码,其实这个只是中国的情况,世界上有很多国家在开始使用计算机时也面临该状况,所以很多国家都开发了自己的字符编码以适应本国的国情,包括但不完全的有以下类型:
- ASCII(美国等使用英语的国家,占1个字节,只支持英文)
- GB2312/GBK(中国字符,占2个字节,支持6700+汉字,而GBK是GB2312的升级版,支持21000+汉字)
- Shift-JIS(日本字符)
- ks_c_5601-1987(韩国编码)
- TIS-620(泰国编码)
常用编码介绍一览表:
编码 | 制定时间 | 作用 | 所占字节数 |
---|---|---|---|
ASCII | 1967年 | 表示英语及西欧语言 | 8bit/1bytes |
GB2312 | 1980年 | 国家简体中文字符集,兼容 ASCII | 2bytes |
Unicode | 1991年 | 国际标准组织统一标准字符集 | 2bytes |
GBK | 1995年 | GB2312 的扩展字符集,支持繁体字,兼容 GB2312 | 2bytes |
UTF-8 | 1992年 | 不定长编码 | 1-3bytes |
各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。例如有一个日本进口的游戏(日本默认使用 Shift-JIS),往自己电脑上一装(中文版的 Windows 字符编码默认是 GBK),就显示乱码了。
因此极大的阻碍不同国家之间的信息传递,这个乱局最终是联合国出面解决的,于是就诞生了下面要说的 Unicode 和 UTF
Unicode 和 UTF
一、Unicode
上面讲到,由于各国之间都开发出了自己的字符编码,导致不同国家之间的信息传递有极大的阻碍。所以 Unicode 编码应运而生,Unicode 编码把所有语言都统一到一套编码里,这样就不会再有乱码问题了。Unicode 编码使用2到4个字节,并且已经收录136690个字符,并还在一直不断扩张中。同时 Unicode 编码标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持 Unicode 编码。
特点:
- 支持全球所有的语言
- 可以跟各种语言的编码自由转换,也就是说,即使你 GBK 编码的文字,想转成 Unicode 编码也很容易
为何 Unicode 编码需要与其他语言的字符编码相互转换呢?这是个历史问题,以中文编码为例,GB2312 最早是在1980年出现的,而 Unicode 编码是1990年才出现的,那在这十年之间无数的计算机应用开发都是使用 GB2312 来开发的,如果突然间要求所有的计算机应用都使用该编码,那几乎就是要求所有使用 GB2312 来开发的计算机应用推倒重来,这换做你应该也会反对吧;并且 GB 系列编码就像汉语在国内一样,而 Unicode 编码就像国际通用语言英语一样,而我们在国内沟通时基本不需要使用英语吧,所以也没有很强烈的需要要求把 GB 系列编码转换成 Unicode 编码。
于是联合国为了推广 Unicode 编码还做了以下努力:
- 联合国要求全球计算机厂商出厂都支持 Unicode
- Unicode 与所有语言编码都做了对应关系(这也是为什么 Unicode 可以与各种语言编码可以自由转换的原因)
而目前为止大多数的计算机应用都支持 Unicode 编码。下图就是 Unicode 编码跟中文编码的对应关系
二、UTF
但是新的问题又出现了!如果统一成 Unicode 编码,乱得问题从此消失了。但是,如果你写的文本基本上全部是英文的话,用 Unicode 编码比 ASCII 码的存储空间需要多一倍,由于计算机的内存比较大,并且字符事在内容中表示时也不会特别大,所以内存可以使用 Unicode 编码来处理,但是存储和网络传输时一般数据都会非常多,那么这多的一倍的存储空间将是无法接受的。
为了解决存储和网络传输的问题,于是出现了 UTF(Unicode Transformation Format),即:对 Unicode 编码进行转换,以便于在存储和网络传输时可以节省空间,UTF 有以下版本:
- UTF-8(主流):使用1、2、3、4个字节表示所有字符,优先使用1个字符、无法满足则增加一个字节,最多4个字节。英文占1个字节、欧洲语系占2个、东亚占3个,其它及特殊字符占4个
- UTF-16:使用2、4个字节表示所有字符,优先使用2个字节,否则使用4个字节表示
- UTF32:使用4个字节表示所有字符
总的来说,UTF 是为 Unicode 编码而设计的一种,在存储和传输时节省空间的编码方案。如果你要传输的文本包含大量英文字符,用 UTF-8 编码就能节省空间,ASCII、Unicode、UTF-8之间的对应如下表所示
字符 | ASCII | Unicode | UTF-8 |
---|---|---|---|
A | 01000001 | 00000000 01000001 | 01000001 |
中 | x | 01001110 00101101 | 11100100 10111000 10101101 |
从上面的表格还可以发现,UTF-8 编码有一个额外的好处,就是 ASCII 码实际上可以被看成是 UTF-8 编码的一部分,所以大量只支持 ASCII 码的历史遗留软件可以在 UTF-8 编码下继续工作。
现代计算机系统通用的字符编码工作方式
目前我们已经对 ASCII、Unicode 和 UTF-8 有了了解,那我们现在总结一下现代计算机系统通用的字符编码工作方式。
在计算机内存中,统一使用 Unicode 编码,当需要保存到硬盘或者需要传输的时候,就转换为 UTF-8 编码。例如用记事本编辑的时候,从文件读取的 UTF-8 字符被转换为 Unicode 字符到内存里,编辑完成后,保存的时候再把 Unicode 转换为 UTF-8 保存到文件。如下图所示
值得一提的还有,如果你的系统编码格式是 UTF-8 编码,而你所写的程序为 GBK 编码,那么也会产生乱码,这是因为 UTF-8 与 GBK 并没有直接关系,之所以他们能转换是因为 Unicode 作为中介,具体如下图所示