早期的计算机只支持英文,所以需要表达的字符数量很少,为此ANSI制定了ASCII字符表,以一个字节的低7位表示字符,这样可以表达128个,当字节的高位为1时,表示的是扩展ASCII字符,ANSI并没有为它们指定标准。
然而,计算机所要表达的并非只有一种语言,为了使ASCII可以支持其他平台,IBM又做了一些修改,利用两个扩展ASCII字符来表达非英文字符,这样可以表达的扩展字符数就到达了14位,即16384个字符。这就是ANSI字符标准。
针 对ANSI每个国家(地区)有自己的编码规范,对中文而言,最早的规范是大家所熟知的大陆的GB2312-80,台湾地区的BIG5以及香港的 HKSCS,后来GB2312发展成GBK,GBK是GB2312的超集,向下兼容,也就是说GB2312的字符编码与GBK相同,只是GBK多了一些字 符定义,现在简体中文的最新编码规范是GB18030,它是GBK的超集,向下兼容,但是据我所知现在还没有哪个操作系统直接支持它。
上面说到的ANSI对英文和其他语言字符编码所需要的字节数不等,或一个或两个,所以被称之为MBCS(多字节编码系统),分辨一个字符占用字节数的办法就是看首位是否为1,如果为1,那么连续的两个字节表述一个字符,否则,是一个ASCII码。
这种编码规范使得各种文字可以在本地化后的计算机系统中正确被处理,但是这里还有个国际化的问题,例如,我们在一个文本文件中同时要显示不同的语言(如中文和日文)时,改怎么办?
因为ANSI针对每种语言的编码没有区分,所以GB2312的一个字符值在BIG5中可能就有另一个字符与之对应,故在读取文本的时候必须要清楚使用什么编码系统,否则就会出现乱码。而对纯文本而言,它的编码方式只能是一种,所以不同语言是不能同时存在的。
这个时候,UNICODE出现了。
UNICODE 使用两个字节对世界上几乎所有的语言进行编码(0x0000-0xFFFF),它可以表达的字符数量为16位,即65536个字符,每种语言的代码段不 同,两个字节所表达的字符是唯一的,所以不同语种可以共存于文本中,然后用系统的UNICODE表进行解码,就可以显示出来。
unicode与ASCII是兼容的,如ASCII的0X76的UNICODE编码就是0X0076。
unicode 的两个字节在处理的时候顺序是不定的,高位字节在前的我们称之为unicode big endian,低位在前的称之为unicode little endian。之所以有这两种编码方式是因为他们对应了intel处理器和Mac处理器的处理方法。对一个字符串,究竟采用什么序列解码呢?这里有个比较 通用的办法BOM,就是在文本的头两个字节插入标志0xFEFF,它叫做"ZERO WIDTH NO-BREAK SPACE"的,是不存在的unicode字符,所以不应该出现在传输中:
FF FE: unicode little endian
FE FF: unicode big endian
unicode并非没有问题的,我们都知道,现在的计算机是以字节为处理单位的,字符串在系统中的表达已经渐渐形成了规范,我们来举个例子:
C 中字符串是以'\0'(0x00)结尾的,当计算机处理的时候看到0x00的时候就知道字符串完了,如果处理的是ANSI编码自然没有问题,可是要命的是 unicode编码中很多字符的两个字节中的一个都是0x00,这样由c处理就会被认为是字符串结束标志,造成错误。解决这个的办法已经有了,就是用 wchar_t表达一个unicode字符,每次读取两个字节,以0x0000表示字符串结束。
另外一个办法就是使用伟大的UTF(UCS Transformation Format )对Unicode进行编码。
UTF是通用字符编码传输格式,根据最小编码单位不同分为分UTF-8(一个字节),UTF-16(两个字节),UTF-32(4个字节)等,我们这里介绍UTF8。
UTF-8
UTF-8将unicode码划分为三段,每一段采用不同的编码方法:
0x0000-0x007F 0x0******* 一个字节, 7bit
0x0080-0x07FF 0x110***** 0x10****** 两个字节,11bit
0x0800-0xFFFF 0x1110**** 0x10****** 0x10****** 三个字节,16位
注意,一个字节的表达完全与ASCII兼容。
我们现在有这么多的unicode编码方式,那么怎么判断一个文本使用的是哪种呢?对windows文本文件txt而言,它利用开头的几个字节来判断:
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.
遗憾的是,ANSI没有办法与UNICODE区分。
最后给大家一个实验环境:
windows 记事本的保存选项有个编码方式,使用不同的编码方式编码文件就会产生不同的文本代码,然后你用ultraedit打开这些不同编码的文本文件,在16进制 模式下查看,就会看到区别了。不过让我困惑的是,不论它的Unicode编码方式是什么,文件代码居然全部都一样,开头全部是FFFE,不知道这是为什 么。如果哪位知道,请跟个贴分享一下。