我把最重要的概念放在了后面,是故意的,这样看文章的人首先会
看到我写的比较风趣的部分,继而对我五体投地;再者不明白概念
的情况下看文章内容,会一头雾水,感觉高深莫测,继而再次对我
五体投地。我们都知道,现在的学术文章,越是让读者雾水的说明
含金量越高,为了达到这样的效果,我把概念放在了最后,仅供想
把Unicode和字符集编码搞明白的人参阅
Unicode
明白了以上这些基础知识,来详细说说已有的字符集编码标准,尤其
是Unicode的来龙去脉。
ASCII及相关标准
地球人都知道ASCII就是美国标准信息交换码的缩写,也知道ASCII规
定用7位二进制数字来表示英文字符,ASCII被定为国际标准之后的代
号为ISO-646。由于ASCII码只使用了7个二进制位,也就是说一个字
节可以表示的256个数字中,它仅使用了0~127这128个码位,剩下的
128个码位便可以用来做扩展,用来表示一些特定语言所独有的字符,
因此对这多余的128个码位的不同扩展,就形成了一系列ISO-8859-*的
标准。例如为英语作了专门扩展的字符集编码标准编号为ISO-8859-1,
也叫做Latin-1,为希腊语所作的扩展编号为ISO-8859-7等,完整的列
表可以参考《Java Internationalization》一书。
Unicode与UCS
整个Unicode项目是由多家计算机软件公司,还包括一些出版行业的公
司共同发起的,从上世纪八十年代就已经开始。地球人都知道,对于日
文,汉字来说,256个码位是远远不够用的(当然,在当时并不是地球
人都知道,起码设计计算机的老美们就不知道,甚至直到今天,还有老
美以为米国是世界上唯一的国家)。解决方法很直观也很明显,那就是
采用码位多到足够包含所需字符数量的编码方案(即俗话说的头痛医头,
脚痛医脚嘛)。这也是Unicode的目标之一,能够包含世界上所有语言
的字符(包括数学符号,音乐符号,象形文字,已经废弃的古文字等
等)。Unicode的另一个设计目标,对今天影响深远,那就是对所有字
符都采用16位编码(即用一个大小不超过216的整数数字给每个字符编
号,注意从这个意义上也可以看出,Unicode是一种编码字符集,而非字
符集编码)。说这个设计目标对现今影响深远,完全不是表扬,因为到
后来连Unicode的设计者也发现,16位编码仅有65536个码位,远远不能
容纳世界上所有的字符,但当意识到这个问题的时候,Unicode大部分的
规范已经制定完毕,也有相当程度的普及,完全推倒重来是不现实的。
这成了一个遗留问题,也是surrogate pair这种蹩脚解决方案的发端。
无独有偶,在1984年,喜欢以繁多的编号糊弄群众的国际标准化组织ISO
也开始着手制定解决不同语言字符数量太大问题的解决方案,这一方案
被称为Universal Character Set(UCS),正式的编号是ISO-10646(记
得么,ASCII是ISO-646,不知这种安排是否是故意的)。还是ISO高瞻
远瞩,一开始就确定了UCS是一个31位的编码字符集(即用一个大小不
超过231的整数数字为每个字符编号),这回真的足以容纳古往今来所有
国家,所有语言所包含的字符了(是的,任何国家,任何小语种都包括,
也不管这些国家是与台湾建交还是与中国大陆建交)。虽然后来他们意
识到,231个码位又实在太多了……
天下大势,分久必合。无论Unicode还是UCS,最初的目的都是杜绝各种
各样名目繁多形式各异互不兼容老死不相往来的私用扩展编码(好啰嗦
的一句话),结果两方确立标准的同时(最初时这两个标准是不兼容
的),又形成了割据,这对建设和谐社会是不利的,违反当今世界和平
与发展的主旋律,中国政府一向反对任何形式的霸权主义和强权政治,对
以米国为首的发达国家……扯远了扯远了。1991年,Unicode联盟与ISO
的工作组终于开始讨论Unicode与UCS的合并问题,虽然其后的合并进行
了很多年,Unicode初版规范中的很多编码都需要被改写,UCS也需要对
码空间的使用进行必要限制,但成果是喜人的。最终,两者统一了抽象
字符集(即任何一个在Unicode中存在的字符,在UCS中也存在),且最靠
前的65535个字符也统一了字符的编码。对于码空间,两者同意以一百一
十万为限(即两者都认为虽然65536不够,但231又太大,一百一十万是
个双方都可接受的码空间大小,也够用,当然,这里说的一百一十万只是个约数),Unicode将码空间扩展到了一百一十万,而UCS将永久性的不
使用一百一十万以后的码位。也就是说,现在再讲Unicode只包含65536
个字符是不对的。除了对已经定义的字符进行统一外,Unicode联盟与ISO
工作组也同意今后任何的扩展工作两者均保持同步,因此虽然从历史的意
义上讲Unicode与UCS不是一回事(甚至细节上说也不是一回事),但现
在提起Unicode,指代两者均无不妥。
UTF-16
概念一节中说过,字符集编码包括编码字符集和编码形式,适用于Unicode
的编码形式多种多样,最常见的有UTF-8,UTF-16与UTF-32。其中UTF-16
占有极重要的地位,因为
1. 在UTF-16中,前65536个最常用的字符其整数表示形式与编码后的形
式完全相同!例如“汉”字的Unicode编号为0x6C49,那么经过UTF-16
编码后存储在计算机上时,它的表示仍为0x6C49!
2. UTF-16提供了surrogate pair机制,使得Unicode中码位大于65536的
那些字符得以表示。
Surrogate pair机制在目前来说实在不常用,甚至连一些UTF-16的实现都不
支持,所以我不打算在这里多加讨论,其基本的思想就是用两个16位的编
码表示一个字符(注意,只对码位超过65536的字符这么做)。Unicode如
此死抱着16这个数字不放,有历史的原因,也有实用的原因。
因此可以这样说,UTF-16是一种对前65536个字符采取直接映射(即在
计算机中使用2个字节表示),对其上的其它字符采用两个16位编码表
示的字符集编码形式(即在计算机中使用4个字节表示这样的字符)。
有了这样的定义,UTF-32则不难理解,UTF-32对任何Unicode中存在的字
符,在计算机中都使用4个字节来,问题只是它对存储空间太过浪费。
UTF-8稍有不同,对Unicode中的前128个字符(也是ASCII定义的基本字
符),UTF-8使用一个字节来表示,而对第0x0080到第0x07FF个字符,
UTF-8使用2个字节表示,对Unicode编号为0x0800到0xD7FF和0xE000到
0xFFFF之间的字符,使用3个字节表示,对编号为0x10000到0x10FFFF的
字符,使用4个字节表示。具体的转换规则,可以参看这篇文章:
《Mapping codepoints to Unicode encoding forms》,其URL为
http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-
AppendixA#sec3。
UTF-8的好处就在于对于频繁使用前128个字符的英文为主的内容进行存储
时,十分节省空间;而有的遗留系统一次只能处理一个字节,这时UTF-8也
成为存储的唯一选择。
记得当初Unicode与UCS还没成家之时,UCS也是需要人爱,需要人疼的,
没有自己的字符编码形式怎么成。UCS-2与UCS-4就扮演了这样的角色。
UCS-4与UTF-32除了名字不同以外,思想完全一样。而UCS-2与UTF-16在
对前65536个字符的处理上也完全相同,唯一区别只在于UCS-2 不支持
surrogate pair机制,即是说,UCS-2只能对前65536个字符编码,对其后
的字符毫无办法。
