计算机各种编码来历及区别

GB2312:

一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,
这样我们就可以组合出大约7000多个简体汉字了。
在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,
连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,
而原来在127号以下的那些就叫"半角"字符了。
一个汉字算两个英文字符!一个汉字算两个英文字符……

GBK:

不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,
不管后面跟的是不是扩展字符集里的内容。
结果扩展之后的编码方案被称为 GBK 标准,
GBK 包括了 GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。

GB18030:

又加了几千个新的少数民族的字,GBK 扩成了 GB18030。

中国的程序员们看到这一系列汉字编码的标准是好的,于是通称他们叫做 "DBCS"(Double Byte Charecter Set 双字节字符集)。
在DBCS系列标准里,
最大的特点是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里,
因此他们写的程序为了支持中文处理,必须要注意字串里的每一个字节的值,
如果这个值是大于127的,那么就认为一个双字节字符集里的字符出现了。


每个国家都搞出自己的一套编码,为了全世界的使用统一,于是有了。。。


ISO (国际标谁化组织)的国际组织决定着手解决这个问题。
他们打算叫它"Universal Multiple-Octet Coded Character Set",简称 UCS, 俗称 "UNICODE"。

UNICODE:
ISO 就直接规定必须用两个字节,也就是16位来统一表示所有的字符,
对于ascii里的那些“半角”字符,UNICODE 包持其原编码不变,只是将其长度由原来的8位扩展为16位,
而其他文化和语言的字符则全部重新统一编码。
由于"半角"英文符号只需要用到低8位,所以其高 8位永远是0,
因此这种大气的方案在保存英文文本时会多浪费一倍的空间。


他们的strlen函数靠不住了,一个汉字不再是相当于两个字符了,而是一个!
是的,从 UNICODE 开始,无论是半角的英文字母,还是全角的汉字,
它们都是统一的"一个字符"!同时,也都是统一的"两个字节",
“字节”是一个8位的物理存贮单元,而“字符”则是一个文化相关的符号。
在UNICODE 中,一个字符就是两个字节。


从 Windows NT 开始,MS 趁机把它们的操作系统改了一遍,
把所有的核心代码都改成了用 UNICODE 方式工作的版本,
从这时开始,WINDOWS 系统终于无需要加装各种本土语言系统,就可以显示全世界上所有文化的字符了。

但是,UNICODE 在制订时没有考虑与任何一种现有的编码方案保持兼容,
这使得 GBK 与UNICODE 在汉字的内码编排上完全是不一样的,
没有一种简单的算术方法可以把文本内容从UNICODE编码和另一种编码进行转换,
这种转换必须通过查表来进行。


UNICODE 是用两个字节来表示为一个字符,他总共可以组合出65535不同的字符,
这大概已经可以覆盖世界上所有文化的符号。如果还不够也没有关系,ISO已经准备了UCS-4方案,
说简单了就是四个字节来表示一个字符,样我们就可以组合出21亿个不同的字符出来(最高位有其他用途),
这大概可以用到银河联邦成立那一天吧!


UNICODE 来到时,一起到来的还有计算机网络的兴起,UNICODE 如何在网络上传输也是一个必须考虑的问题,
于是面向传输的众多 UTF(UCS Transfer Format)标准出现了,
顾名思义,UTF8就是每次8个位传输数据,而UTF16就是每次16个位,
只不过为了传输时的可靠性,从UNICODE到 UTF时并不是直接的对应,而是要过一些算法和规则来转换。


从网上引来一段从UNICODE到UTF8的转换规则:

Unicode
UTF-8

0000 - 007F
0xxxxxxx

0080 - 07FF
110xxxxx 10xxxxxx

0800 - FFFF
1110xxxx 10xxxxxx 10xxxxxx


例如"汉"字的Unicode编码是6C49。6C49在0800-FFFF之间,
所以要用3字节模板:1110xxxx 10xxxxxx 10xxxxxx。
将6C49写成二进制是:0110 1100 0100 1001,
将这个比特流按三字节模板的分段方法分为0110 110001 001001,
依次代替模板中的x,得到:1110-0110 10-110001 10-001001,
即E6 B1 89,这就是其UTF8的编码。

当一个软件打开一个文本时,它要做的第一件事是决定这个文本究竟是使用哪种字符集的哪种编码保存的。软件一般采用三种方式来决定文本的字符集和编码:
检测文件头标识,提示用户选择,根据一定的规则猜测
最标准的途径是检测文本最开头的几个字节,开头字节 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.


ANSI字符集:ASCII字符集,以及由此派生并兼容的字符集,
如:GB2312,正式的名称为MBCS(Multi-Byte Chactacter System,多字节字符系统),
通常也称为ANSI字符集。

big endian和little endian
big endian和little endian是CPU处理多字节数的不同方式。
例如“汉”字的Unicode编码是6C49。那么写到文件里时,
究竟是将6C写在前面,还是将49写在前面?
如果将6C写在前面,就是big endian。
还是将49写在前面,就是little endian。

从ASCII、GB2312、GBK到GB18030,这些编码方法是向下兼容的,
即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。


UTF-8就是以8位为单元对UCS进行编码。

UTF-16以16位为单元对UCS进行编码。
对于小于0x10000的UCS码,UTF-16编码就等于UCS码对应的16位无符号整数。
对于不小于 0x10000的UCS码,定义了一个算法。
不过由于实际使用的UCS2,或者UCS4的BMP必然小于0x10000,
所以就目前而言,可以认为UTF -16和UCS-2基本相同。
但UCS-2只是一个编码方案,UTF-16却要用于实际的传输,
所以就不得不考虑字节序的问题。

我很早前就发现Unicode、Unicode big endian和UTF-8编码的txt文件的开头会多出几个字节,
分别是FF、FE(Unicode),FE、FF(Unicode big endian),EF、BB、BF(UTF-8)。
但这些标记是基于什么标准呢?

即读取文件时,
若为unicode时,前两个字节可以不用读取。注:固定是两个字节一个字。
若为utf-8时,前三个字节可以不用读取。
若为ansi时,前面没有多余字节,可从文件头直接读取。

posted @ 2010-06-03 15:42  landylee  阅读(1087)  评论(1编辑  收藏  举报