闲谈字符和字符集以及编码(下)

在本文的上篇中,大致介绍了一下字符集是个什么东西,以及与汉字相关的几个字符集的发展历程,在接下来的这个部分里,我计划谈一谈上篇文末所提到的那两个东西,一个是 UCS,一个是 UTF。

需要提前说明的是,有关 Unicode 的信息在网上的散布很零散,有的信息被广泛传播但是已经过时,甚至有的文中都没有表明该文撰写的时间点,比较权威的信息源,例如 Wikipedia,对于某些词条的解释也是模糊不清甚至互相冲突的。因此,我这本部分中所写的,将会是网络信息与我自己个人知识的杂糅,而且出于题中的“闲谈”二字,某些信息的出处来源我也不会完全标明。

UCS,是 Universal Character Set 的首字母缩写,还有一种说法是,它是 Unicode Character Set 的首字母缩写。可奇怪的是,据说 Unicode 的正式名称是 Universal multiple-octet coded character set,也可以写作 UCS。到这里,笔者已经差不多晕了,敬请方家指正。我个人倾向于前者,因为从各方面的信息来看,UCS 都是一个和 ISO10646 关系紧密的术语,很少有人在 Unicode 相关的上下文中使用,即使有,也可能是一些写作不是那么严谨的文章的误用。

UCS 有两种,UCS-2 和 UCS-4。用两个字节来对 UCS 字符进行编码的方案,称之为 UCS-2,同理,用四个字节对 UCS 字符进行编码的方案,称之为 UCS-4。UCS 的这两种编码都是定长的,也就是说,只要给定字符的个数,那么用以编码这些字符的字节数量就已经确定,无非是乘以二还是四的区别。在 UCS 里,只可能存在没有被指定的代码点(即对某个代码点没有赋予确定的字符),而不存在不能使用的代码点。通过这些可以知道,UCS-2 最多只能表示 65536 个字符。
在我的印象里,最开始在 Windows 下接触 Unicode 就是其号称有 65536 个码位,几乎可以容纳世界上所有语言的字符。这个认识一直深深地烙印在我的大脑里,甚至在后来,明明知道光是汉字的个数就已经超过了 65536 而达到了 7 万多,也没有能导致我去质疑两个字节已经不够对所有的 Unicode 字符进行编码了。不过从我刚才找到的 Unicode 1.1 的相关信息来看,代码点只定义到了 U+FFFD,还没有脱出 65536 的范围,两个字节在当时的确是够用的(从而可知,我的认知错误在于没有能够与时俱进,不清楚后来 Unicode 的发展)。

如果你只对某个字符在 Unicode 字符集中的代码点有兴趣,那显然不需要考虑这个代码点的数值究竟用多少个字节来表示,可当你要落实到计算机程序上,要对之进行存储或者传输时,那么一个代码点到底要占用多大的空间就必须要确定下来了。正好比在 C 语言中,给你一个数字 1,你是计划用一个 char 型的数据呢还是一个 short 的数据,或者是 int 甚至 long?在这个事情上,Unicode 规范中给出了三个官方的方案,分别是 UTF-8、UTF-16 和 UTF-32。UTF 这三个字母后面的数字是各个方案中最小编码单元占用的位数,除以 8 就是字节数了。也就是说,如果是 UTF-8,编码一个 Unicode 字符最少会用 1 个字节,UTF-16 和 UTF-32 则分别是 2 个、4 个。请注意,说的是最少,还没封顶呢。那么最大呢?在本文中限于篇幅,不再给出各个方案的具体编码规则,只说一下结论:UTF-8 编码,目前对一个字符最长是 3 个字节(当然也可能是 2 个),要是采用 UTF-16,则一个 Unicode 字符的编码可能是 2 个字节或者 4 个字节(不可能是 3 个),要是 UTF-32,那是定死的,就是 4 个字节。计算机基础扎实的读者在这儿应该马上就产生一个疑惑,因为会想到超过一个字节的数据在排列时一定会有字节序的问题。这是没错的,也因此,UTF-16 有两种形式,称之为 UTF-16LE 和 UTF-16BE,分别对应小端字节序和大端字节序,UTF-32 同理。如果你对字节序的问题有所困惑,请参阅拙文《字节那些事儿》。对于绝大部分的两个字节可以表示的字符,UTF-16 和 UCS-2 的编码是一样的,这个绝大部分如果用数字来说,是 96.9%。但 UTF-16 的优势在于,对于超出两个字节表示范围的字符,它也有办法来编码,只是增加了编码的长度而已,而 UCS-2 则就无能为力了。
一旦表示一个字符已经达到了要动用 4 个字节的地步,和谐的面貌就开始出现了,UCS-4 和 UTF-32 成了一模一样的东西,没有任何差异,互为别名而已。ISO 组织和 Unicode 组织甚至在将来指定新的字符的代码点上也达成了一致,以保证相互兼容的长治久安局面。

最后顺便要提一下,在历史上还出现过一些其他的编码方案,例如 UTF-1,UTF-7(甚至还有 UTF-9 和 UTF-18,不过千万注意,这两个是被作为愚人节笑话发出来的,别像国内一些媒体一样上了这种当,当了真),这些东西,绝大部分已经不再鲜活了,除非有很大必要,是无需去做深入了解的,当然,如果谁喜欢把自己修炼成计算机历史学家,尽管去精研无妨。

在本文里还有两个和 UTF 有关的术语没有解释,一个是 BOM,全称 Byte Order Mark,即字节序标记,还有一个是 ZWNBSP,全称 Zero Width Non Breaking Space,是为零宽度非换行空白。有兴趣可以自行搜索,它们引发的歧义并不多,而且失之于过于琐细,所以不是本文的介绍对象。
对于 UCS 和 UTF 的大致介绍就到这里了,这后一篇写得不算多,却费了很大的劲,因为斟酌哪些信息要放进来,哪些要舍弃着实不容易。希望能够达到我的小小初衷,能让看到此文的朋友在短时间内了解到这些相关概念、术语的概貌。若果如此,幸甚至哉。

参考资料
1、http://www.elfdata.com/plugin/unicodefaqdata.html
2、http://www.cl.cam.ac.uk/~mgk25/unicode.html
3、http://en.wikipedia.org/wiki/UTF-8
4、http://en.wikipedia.org/wiki/UTF-16
5、http://en.wikipedia.org/wiki/UTF-32

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注