首先,阐明几个基本概念。字符集,编码方案,编码范围,编码方法,编码位数,兼容性,编码兼容性。

字符集是指一系列符号的集合。计算机中只能处理数字,因此符号必须给予编码,而后储存符号编码。打印时按照编码索引到符号,再索引到字体。因此一个字符集编码为数字的方案就是编码方案。其中西文编码规范就是ASCII(ISO-8859-1)。

编码范围是指字符集的有效符号编码的范围。例如当前的ASCII编码范围是0-127,因此所有兼容ASCII的编码,其编码范围必定要回避0-127,否则就会出现编码冲突。而编码方法(不等同于编码方案)则是这个数字转换为计算机内数据的方法,一般分big endian(大端点)和little endian(小端点)两种。

big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian。“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。

当然,编码方法还有其他情况,例如UTF-8就也是一种编码方法,叫做非等长编码。非等长编码在安全性,扩充性和兼容性上优于等长编码,但是使用起来效率非常差。不信的可以用windows中的_mbsdec函数看看,除了当前指针,还需要起始指针进行逆遍历,效率可想而知。

在大端点和小端点的情况下,存储一个符号所需要用的位数叫做编码位数。位数分为固定位数和浮动位数。又因为编码位数一般都为8的整数倍,因此一般都使用编码字节数来代替。

兼容是指一个字符集的文字在另外一个字符集中全部存在。所以,A字符集兼容B,一般B字符集不兼容A,否则两者就相同了。编码兼容性是指一个字符集的文字在另外一个字符集中全部存在,并且同一文字表示的编码一致。可以想见,编码兼容的字符集本身一定兼容。

其次,GB3212, GBK, GB18030, BIG5, CNS11643, CJK, Unicode, UCS-2, UTF-8的区别。

简体中文来说,基本是GB系列的大陆地区简体中文国家标准,全部都是向下编码兼容的(附注:存在部分的兼容错误)。有GB3212, GBK, GB18030三个标准。编码方案都是兼容小端点序。(GB18030有变长编码)

1980年制定的GB2312是国家早期的字符编码规范。一共收录了7445个字符,范围是0xA1A1 - 0xFEFE。现在意义基本等同于国家最小字符编码集。支持中文的产品最小要支持所有GB2312字符的显示。

1995年制定的汉字扩展规范GBK1.0,简称GBK。收录了21886个符号,范围是0x8140 - 0xFEFE。现在多数电脑的字符集都是这个,向下编码兼容GB2312标准。

2000年的GB18030是取代GBK1.0的正式国家标准,该标准收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。编码是变长的,其二字节部分与GBK兼容;四字节部分是扩充的字形、字位,其编码范围是首字节0x81-0xfe、二字节0x30-0x39、三字节0x81-0xfe、四字节0x30-0x39。向下编码兼容GBK1.0,当前使用中,GB18030和GBK的区别一般人无法区分(也没有多少人碰的上这种字),所以一般GBK就通用指代了GB系列中比较复杂的那种编码。

繁体中文来说,有BIG5, CNS11643, HKSCS三种。贝壳实际应用比较少,下面可能存在错误,请大家指正。

BIG5是在CCCII不為政府單位採納,國家頒布的中文標準碼又不堪用的情況下。在1984年,由台北市電腦公會主導,聯合了十三家業者,

共同制定,并在2003年进行了修订(Big5-2003),旨在提供一个小型基本字符集以便对当前的繁体中文字符进行编码。Big5-2003是Big5的扩展,仅有2个平面,包含13051个繁体中文字符和778个符号,共13829个字符。编码范围是0xA140 - 0xF9FE, 0xA1A1 - 0xF9FE。对于熟悉电脑的人来说,都知道Big5是繁体字的事实标准。

CNS11643在1992年制定,并在2004年进行了修订(称为CNS11643-2004),旨在提供足够的字符编码以便对所有当前的繁体中文字符进行编码。CNS11643-2004是CNS11643的扩展,可以有 80 个编码平面。该标准支持: 8836 x 80 = 706,880 个编码点。原来的CNS11643标准仅有16个编码平面。在平面4以及平面12到15中,包含了台湾地区政府允许的所有法定人名用繁体中文字符。CNS11643直接取用了Big5的大部分编码,因此不考虑几个特例的情况下(准确的说,是两个),CNS11643编码兼容了Big5。

香港增补字符集(HKSCS)原来叫做政府通用字库(GCCS),分两个编码方案。其中Big5版是香港政府为big5加的3049个字,因此也可以说HKSCS编码兼容了BIg5。ISO 10646方案是香港政府在给Big5添加符号后向ISO标准委员会提交了申请的结果,和Big5的版本互相兼容,只是编码方案(不是编码方法)不一致而已。

再附加一点说明,一般我们说的编码转换,就是在Big5和GB2312间转换。鉴于繁体和简体文字的非严格对应性,转换可能存在误差。至于最大字符集组GB18030和CNS11643间的完美转换——还是等世界和平吧。

下面说明Unicode家族,根据网络上的介绍,原来Unicode联盟和ISO标准组织都要对整个人类的符号进行编码工作(背景音乐:数星星啊数星星~××),后来两者联合,这事就成了(it was so,玩笑玩笑)。大家知道,中国文件和东南亚各国间互相交流,因此字符重复者甚众。其中CJK是原来中国(包括香港、台湾地区)与朝鲜、韩国、日本联合制定的三国文字集合,现在已经被收入Unicode中。Unicode是一个单纯的编码方案,不过编码方法就相对复杂了,分为UCS-2,UCS-4,UTF-8等等。

UCS-2和UCS-4是等长编码方法,简单来说就是U+65535以内的可以编码入UCS-2,以上就需要使用UCS-4了(目前这个范围还没有启用)。UCS-2总共有65535个编码点,又叫做UCS-4的BMP区域。本质上是使用大端点或者小端点编码方法直接编码,可以在字符串开始的地方加入FF FE或者FE FF加以判别。优点是将所有字符熔於一个体系,没有编码冲突问题,因此可以在一个容器内引用多国文字(例如在同一句话中引用简体和繁体中文),效率非常高,但是有个致命缺点,不兼容ASCII。

为了解决这个问题,我们一般使用Unicode的时候,使用它的UTF-8编码方法。这个编码方法是非等长的,其中多数汉字需要使用三字节来存储。如果您看到有什么中文变成乱码后长度增加了一半的,那多数就是UTF-8编码。对于ASCII,UTF-8就是一字节码,于是就完整的兼容了ASCII。对于UCS-4中可能出现的最大编码来说,这时候就需要六字节来描述一个符号。因此可以想见,将来UTF-8是一定要灭亡的。

Reference:

[1].谈谈Unicode编码 http://www.windsn.com/article/viewmore.asp?id=227

[2].中文编码基础知识介绍 http://www.eygle.com/digest/2007/01/zhs16gbk_char.html

[3].The CJK package for LaTeX http://cjk.ffii.org/

[4].編碼標準 http://itbbs.saihu.com/archiver/tid-1943.html

[5].《香港增補字符集》 http://www.info.gov.hk/digital21/chi/hkscs/introduction.html

[6].Unicode Home Page http://www.unicode.org/