在最初的时候,Internet上只有一种字符集—— ANSI的ASCII字符集,它使用7 bits来表示一个字符,总共表示128个字符,其中包括了英文字母、数字、标点符号等常用字符。之后,又进行扩展,使用8 bits表示一个字符,可以表示256个字符,主要在原来的7 bits字符集的基础上加入了一些特殊符号例如制表符。
后来,由于各国语言的加入,ASCII已经不能满足信息交流的需要,因此,为了能够表示其它国家的文字, 各国在ASCII的基础上制定了自己的字符集,这些从ANSI标准派生的字符集被习惯的统称为ANSI字符集,它们正式的名称应该是MBCS(Multi-Byte Chactacter System,即多字节字符系统)。这些派生字符集的特点是以ASCII 127 bits为基础,兼容ASCII 127,他们使用大于128的编码作为一个Leading Byte,紧跟在Leading Byte后的第二(甚至第三)个字符与Leading Byte一起作为实际的编码。这样的字符集有很多,我们常见的GB-2312就是其中之一。
例如在GB-2312字符集中,“连通”的编码为C1 AC CD A8,其中C1和CD就是Leading Byte。前127个编码为标准ASCII保留,例如“0”的编码是30H(30H表示十六进制的30)。软件在读取时,如果看到30H,知道它小于128就是标准ASCII,表示“0”,看到C1大于128就知道它后面有一个另外的编码,因此C1 AC一同构成一个整个的编码,在GB-2312字符集中表示“连”。
由于每种语言都制定了自己的字符集,导致最后存在的各种字符集实在太多,在国际交流中要经常转换字符集非常不便。因此,提出了Unicode字符集,它固定使用16 bits(两个字节、一个字)来表示一个字符,共可以表示65536个字符。将世界上几乎所有语言的常用字符收录其中,方便了信息交流。 标准的Unicode称为UTF-16。后来为了双字节的Unicode能够在现存的处理单字节的系统上正确传输,出现了UTF-8,使用类似MBCS的方式对Unicode进行编码。注意UTF-8是编码,它属于Unicode字符集。Unicode字符集有多种编码形式,而ASCII只有一种,大多数MBCS(包括GB-2312)也只有一种。
Unicode的最初目标,是用1个16位的编码来为超过65000字符提供映射。但这还不够,它不能覆盖全部历史上的文字,也不能解决传输的问题 (implantation head-ache's),尤其在那些基于网络的应用中。已有的软件必须做大量的工作来程序16位的数据。因此,Unicode用一些基本的保留字符制定了三套编码方式。它们分别是UTF-8,UTF-16和UTF-32。正如名字所示,在UTF-8中,字符是以8位序列来编码的,用一个或几个字节来表示一个字符。这种方式的最大好处,是UTF-8保留了ASCII字符的编码做为它的一部分,例如,在UTF-8和ASCII中,“A”的编码都是0x41.UTF-16和UTF-32分别是Unicode的16位和32位编码方式。考虑到最初的目的,通常说的Unicode就是指UTF-16。
例如“连通”两个字的Unicode标准编码UTF-16 (big endian)为:DE 8F 1A 90
而其UTF-8编码为:E8 BF 9E E9 80 9A
最后,当一个软件打开一个文本时,它要做的第一件事是决定这个文本究竟是使用哪种字符集的哪种编码保存的。软件有三种途径来决定文本的字符集和编码:
最标准的途径是检测文本最开头的几个字节,如下表:
开头字节 Charset/encoding
EF BB BF UTF-8
FE FF UTF-16/UCS-2, little endian
FF FE UTF-16/UCS-2, big endian
FF FE 00 00 UTF-32/UCS-4, little endian.
00 00 FE FF UTF-32/UCS-4, big-endian.例如插入标记后,连通”两个字的UTF-16 (big endian)和UTF-8码分别为:
FF FE DE 8F 1A 90
EF BB BF E8 BF 9E E9 80 9A
但是MBCS文本没有这些位于开头的字符集标记,更不幸的是,一些早期的和一些设计不良的软件在保存Unicode文本时不插入这些位于开头的字符集标记。因此,软件不能依赖于这种途径。这时,软件可以采取一种比较安全的方式来决定字符集及其编码,那就是弹出一个对话框来请示用户,例如将那个“连通”文件拖到MS Word中,Word就会弹出一个对话框。
如果软件不想麻烦用户,或者它不方便向用户请示,那它只能采取自己“猜”的方法,软件可以根据整个文本的特征来猜测它可能属于哪个charset,这就很可能不准了。使用记事本打开那个“连通”文件就属于这种情况。
我们可以证明这一点:在记事本中键入“连通”后,选择“Save As”,会看到最后一个下拉框中显示有“ANSI”,这时保存。当再当打开“连通”文件出现乱码后,再点击“File”->“Save As”,会看到最后一个下拉框中显示有“UTF-8”,这说明记事本认为当前打开的这个文本是一个UTF-8编码的文本。而我们刚才保存时是用ANSI字符集保存的。这说明,记事本猜测了“连通”文件的字符集,认为它更像一个UTF-8编码文本。这是因为“连通”两个字的GB-2312编码看起来更像UTF-8编码导致的,这是一个巧合,不是所有文字都这样。可以使用记事本的打开功能,在打开“连通”文件时在最后一个下拉框中选择ANSI,就能正常显示了。反过来,如果之前保存时保存为UTF-8编码,则直接打开也不会出现问题。
如果将“连通”文件放入MS Word中,Word也会认为它是一个UTF-8编码的文件,但它不能确定,因此会弹出一个对话框询问用户,这时选择“简体中文(GB2312)”,就能正常打开了。记事本在这一点上做得比较简化罢了,这与这个程序的定位是一致的。
需要提醒大家的是,部分Windows 2000字型无法显示所有的Unicode字符。如果发现文件中缺少了某些字符,只需将其变更为其它字型即可。
big endian和little endian
big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian。
“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。
我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。
Unicode big endian:在Big-endian处理器(如苹果Macintosh电脑)上建立的Unicode文件中的文字位元组(存放单位)排列顺序,与在Intel处理器上建立的文件的文字位元组排列顺序相反。最重要的位元组拥有最低的地址,且会先储存文字中较大的一端。为使这类电脑的用户能够存取你的文件,可选择Unicode big-endian格式。
什么是 UCS 实现级别?
不是所有的系统都需要支持象组合字符这样的 UCS 里所有的先进机制. 因此 ISO 10646 指定了下列三种实现级别:
级别1
不支持组合字符和 Hangul Jamo 字符 (一种特别的, 更加复杂的韩国文的编码, 使用两个或三个子字符来编码一个韩文音节)
级别2
类似于级别1, 但在某些文字中, 允许一列固定的组合字符 (例如, 希伯来文, 阿拉伯文, Devangari, 孟加拉语, 果鲁穆奇语, Gujarati, Oriya, 泰米尔语, Telugo, 印.埃纳德语, Malayalam, 泰国语和老挝语). 如果没有这最起码的几个组合字符, UCS 就不能完整地表达这些语言.
级别3
支持所有的 UCS 字符, 例如数学家可以在任意一个字符上加上一个 tilde(颚化符号,西班牙语字母上面的~)或一个箭头(或两者都加).
什么是 Unicode?
历史上, 有两个独立的, 创立单一字符集的尝试. 一个是href="http://www.iso.ch/">国际标准化组织(ISO)的 ISO 10646 项目, 另一个是由(一开始大多是美国的)多语言软件制造商组成的协会组织的 Unicode 项目. 幸运的是, 1991年前后, 两个项目的参与者都认识到, 世界不需要两个不同的单一字符集. 它们合并双方的工作成果, 并为创立一个单一编码表而协同工作. 两个项目仍都存在并独立地公布各自的标准, 但 Unicode 协会和 ISO/IEC JTC1/SC2 都同意保持 Unicode 和 ISO 10646 标准的码表兼容, 并紧密地共同调整任何未来的扩展.
那么 Unicode 和 ISO 10646 不同在什么地方?
Unicode 协会公布的 Unicode 标准 严密地包含了 ISO 10646-1 实现级别3的基本多语言面. 在两个标准里所有的字符都在相同的位置并且有相同的名字.Unicode 标准额外定义了许多与字符有关的语义符号学, 一般而言是对于实现高质量的印刷出版系统的更好的参考. Unicode 详细说明了绘制某些语言(比如阿拉伯语)表达形式的算法, 处理双向文字(比如拉丁与希伯来文混合文字)的算法和排序与字符串比较所需的算法, 以及其他许多东西. 另一方面, ISO 10646 标准, 就象广为人知的 ISO 8859 标准一样, 只不过是一个简单的字符集表. 它指定了一些与标准有关的术语, 定义了一些编码的别名, 并包括了规范说明, 指定了怎样使用 UCS 连接其他 ISO 标准的实现, 比如 ISO 6429 和 ISO 2022. 还有一些与 ISO 紧密相关的, 比如 ISO 14651 是关于 UCS 字符串排序的. 考虑到 Unicode 标准有一个易记的名字, 且在任何好的书店里的 Addison-Wesley 里有, 只花费 ISO 版本的一小部分, 且包括更多的辅助信息, 因而它成为使用广泛得多的参考也就不足为奇了. 然而, 一般认为, 用于打印 ISO 10646-1 标准的字体在某些方面的质量要高于用于打印 Unicode 2.0的. 专业字体设计者总是被建议说要两个标准都实现, 但一些提供的样例字形有显著的区别. ISO 10646-1 标准同样使用四种不同的风格变体来显示表意文字如中文, 日文和韩文 (CJK), 而 Unicode 2.0 的表里只有中文的变体. 这导致了普遍的认为 Unicode 对日本用户来说是不可接收的传说, 尽管是错误的.