计算机起初是设计用来做数学计算的,Computer 一词英文原意是“计算员”——在计算机发明之前,计算员是一个独立的职业,专门做各种数学用表的计算,如测量和天文领域的三角函数表、对数表,航海领域的航海天文历等。
计算机发明后不久,人们发现,这玩意除了能当计算员,还能当文员,用来处理人类社会的非数字信息。然而,计算机在设计上是只认识数字的(具体说是只认识二进制数字),要想让它能够识别并处理人类符号,就必须采取某种翻译手段,在计算机的二进制数字和人类的符号之间做双向转换。
这种字符-数字的映射(转换)关系本质上就是一张查找表,在理论上是很简单的。我们先给人类的每个字符分配一个独一无二的编号(character code,字符编码),如图:
然后通过外设(键盘)将字符输入到计算机中,比如我们键盘上针对A、B、C分别都有按键。当我们按下“A”后,计算机通过查找表得知该字符的编码是十进制 1,便使用二进制 00000001 在内部表示和存储起来。
光存储还不行,我们还要将计算机中的字符(编号)显示或打印出来,所以还涉及到字库。在显示器上显示某个字符,本质上是在一个nn 的像素点阵中,让某些位置的像素设置为黑色(用 1 表示),其它位置为白色(用 0 表示),比如中文“你”的点阵图(注意不同字库的点阵图不同):
这样一个 1616 的像素矩阵,需要 16 * 16 / 8 = 32 字节的空间来表示,右边的“字模信息”称为字形编码。不同的字库(如宋体、黑体)对同一个字符的字形编码是不同的。
这里每个像素只需要黑、白两种颜色,只需要一个位就行了,如果是彩色,则理论上需要 3 字节(RGB)来表示(当然这里没考虑压缩算法)。
所以这里涉及到另一张查找表:字符编码-字形编码的映射关系:
计算机根据用户指定的字库从中查出字符编码对应的字形编码值,输送给相应的图形处理程序进而显示出来相应的字符。
整个输入-转码存储-输出(显示/打印)的流程简单表示如下:
对于英文字符,直接在键盘上敲就行了,对于其他字符比如中文,则不是那么直观,因为键盘无论如何也放不下那么多汉字,所以又要用到另一层转换。我们称计算机内部那个字符编码称为内码,而外部用户输入用到的叫做外码,比如中文输入法用到的外码有拼音、五笔码、仓颉码等,对于这种情况,还需要做一次外码到内码的映射。
文字处理系统需要考虑的事情非常多,绝非简单进行编码映射就行。比如英文单词的换行、英文单词的大小写、中文的横排竖排、阿拉伯语的连字处理等,文字处理系统需要能够正确处理特定语言上下文。
我们接下来重点讲上图中“字符编码”这块。
源于美国
用今天的眼光看,这世界存在各种各样的字符编码标准,什么ASCII、 ISO-8859-1、GBK、Big5、Unicode 等——你有没有想过,单单一个字符编码,为啥会有这么多标准?这不是成心让程序员头大吗?
现实中的标准从来都不是由某权威机构事先制定的,而是一些公司因自身需求(市场拓展需要)而发明出来一套游戏规则。每家公司都根据自身情况发明自己的游戏规则,各家之间规则彼此不同,自己玩没事,跑到一起玩(互操作)就哑巴了。于是要么标准制定机构(如国家标准委员会、ISO 等)站出来,要么几家龙头企业凑到一起成立个某某联盟,总之大家都有一个目标:统一游戏规则。
套用鲁迅先生一句话就是:这世间本没有标准,玩得人多了,便成了标准。
只有从这个角度看问题,才能理解为啥会存在那么多字符集编码标准,为啥要有 Unicode,而 Unicode 的一些实现为啥怪怪的。
1964 年,IBM 推出其划时代的大型机 System/360(怎么个划时代请自行百度),为该大型机设计的字符集编码标准叫 EBCDIC(Extended Binary Coded Decimal Interchange Code,扩展二进制编码的十进制交换码),这是一个单字节编码方案,囊括了一些控制字符、数字、常用标点、大小写英文字母:
EBCDIC 编码。图片来自百度百科
图中行号表示字节高 4 位,列号表示字节低 4 位,行、列分别是十六进制 0~F,如 0x81 表示 a,0xC1 表示 A。注意表中英文单词不是连续的,这给程序处理带来些许麻烦。
4 年后,美国国家标准学会 ANSI(American National Standard Institute) 于 1968 年发布了著名的 ASCII(American Standard Code for Information Interchange美国信息交换标准码) 编码标准。ASCII 和 EBCDIC 一样是单字节编码,不过它吸取了 EBCDIC 的经验教