文字编码的前世今生
Unicode应用中最容易把人搅晕的就是各种不同的Unicode编码方案,以至于从ASCII及GB2312时代跨入Unicode时代的我,很长时间一直以为Unicode和UTF-8就是同一个东西,这样自然会在Python环境下吃不少亏,多次碰壁后好好阅读学习了很多资料,总算是把文字编码的问题基本弄清楚了。回头详细审视文字在计算机中的编码演化的问题,其实我们很多程序设计教材在写这个问题的时候都没把这个问题彻底讲清楚,可能是篇幅的原因,也有可能部分作者自己也没有吃透这个问题吧。总之,能够把整个文字编码到底有些什么,各种编码彼此之间又是什么关系,特别是这些编码方案背后的原因,为什么要这样设计编码?一直是困扰我的一大问题。
下学期的《Python程序设计》课程计划结合自己的最近的理解感悟改改课件,因此,先在这把相关东西总结一下。
第一节 拼读语言的文字编码——ASCII、latin1及ISO8859
文字的编码自然是从英语言世界ASCII开始的,7位二进制从00-7F,编码常用的英文大小写字母、数字、标点和不可见的一些控制字符,总共128个字符,学过计算机程序设计的人应该对ASCII都不陌生,这个没什么必要再说,C语言时代就是这些,具体的编码表可参看:http://ascii.911cha.com/
接下来的扩展就是西方和英语世界最接近的西欧拉丁字母扩展,在ASCII字符集的基础上增加了A0-FF编码的96个西欧字符,实现了对大部分西欧语言(包括西班牙语、葡萄牙语、意大利语、德语、以及部分法语字符)的编码,扩展编码见:http://ascii.911cha.com/eascii.html
这一编码规范也成为了国际编码规范ISO/IEC 8859-1,在程序设计领域一般叫做latin1编码,编码表如下图:
latin1再加上一些控制字符就构成了完整的8位二进制表示,这也就是IBM-PC中最早的文字编码了(注:IBM-PC文字编码比latin1标准稍早,细节上也略有不同),也即是C语言的char类型的来源。
要输入latin1的扩展字符的话,由于我们使用的是英文键盘没有重音的拉丁字符,这时候可以查latin1编码表,以小写ae连体字符为例,其十六进制编码为E6,在Python中可以这样处理:
>>> t=b'\xE6'
>>> t
b'\xe6'
>>> t.decode('latin1')
'æ'
这样就得到了小写连体ae的拉丁字符。
在latin1之后,文字编码开始扩展到其他的字母拼读文字,ISO/IEC 8859-1之后又陆续出现了14个同系列的国际标准,实现了对大部分拼读文字的数字化编码,具体标准如下:
ISO/IEC 8859-1 (Latin-1) - 西欧语言
ISO/IEC 8859-2 (Latin-2) - 中欧语言
ISO/IEC 8859-3 (Latin-3) - 南欧语言。世界语也可用此字符集显示。
ISO/IEC 8859-4 (Latin-4) - 北欧语言
ISO/IEC 8859-5 (Cyrillic) - 斯拉夫语言
ISO/IEC 8859-6 (Arabic) - 阿拉伯语
ISO/IEC 8859-7 (Greek) - 希腊语
ISO/IEC 8859-8 (Hebrew) - 希伯来语(视觉顺序)
ISO 8859-8-I - 希伯来语(逻辑顺序)
ISO/IEC 8859-9 (Latin-5 或 Turkish) - 它把Latin-1的冰岛语字母换走,加入土耳其语字母。
ISO/IEC 8859-10 (Latin-6 或 Nordic) - 北日耳曼语支,用来代替Latin-4。
ISO/IEC 8859-11 (Thai) - 泰语,从泰国的 TIS620 标准字集演化而来。
ISO/IEC 8859-13 (Latin-7 或 Baltic Rim) - 波罗的语族
ISO/IEC 8859-14 (Latin-8 或 Celtic) - 凯尔特语族
ISO/IEC 8859-15 (Latin-9) - 西欧语言,加入Latin-1欠缺的芬兰语字母和大写法语重音字母,以及欧元符号。
ISO/IEC 8859-16 (Latin-10) - 东南欧语言。主要供罗马尼亚语使用,并加入欧元符号。
由于一个字节8位,最多编码256个字符,已经被latin1字符集和相关控制字符占满了。这样,其他的字符编码如何同latin1的字符区别呢?一个普通文本文件究竟是用那种编码方案进行编码的呢?单纯从编码值上,现在已经无法回答这个问题。要实现对latin1之外的字符的支持,这时出现了编码页CP&#x