ASCII(American
Standard Code for Information Interchange)
美国信息交换标准代码,这是计算机上最早使用的通用的编码方案。那个时候计算机还只是拉丁文字的专利,根本没有想到现在计算机的发展势头,如果想到了,可能一开始就会使用
unicode
了。当时绝大部分专家都认为,要用计算机,必须熟练掌握英文。这种编码占用
7
个
Bit
,在计算机中占用一个字节,
8
位,最高位没用,通讯的时候有时用作奇偶校验位。因此
ASCII
编码的取值范围实际上是:
0x00-0x7f,
只能表示
128
个字符。后来发现
128
个不太够用,做了扩展,叫做
ASCII
扩展编码,用足八位,取值范围变成:
0x00-0xff,
能表示
256
个字符。其实这种扩展意义不大,因为
256
个字符表示一些非拉丁文字远远不够,但是表示拉丁文字,又用不完。所以扩展的意义还是为了下面的
ANSI
编码服务。
ANSI
(
American
National Standard Institite
)
美国国家标准协会,也就是说,每个国家(非拉丁语系国家)自己制定自己的文字的编码规则,并得到了
ANSI
认可,符合
ANSI
的标准,全世界在表示对应国家文字的时候都通用这种编码就叫
ANSI
编码。换句话说,中国的
ANSI
编码和在日本的
ANSI
的意思是不一样的,因为都代表自己国家的文字编码标准。比如中国的
ANSI
对应就是
GB2312
标准,日本就是
JIT
标准,香港,台湾对应的是
BIG5
标准等等。当然这个问题也比较复杂,微软从
95
开始,用就是自己搞的一个标准
GBK
。
GB2312
里面只有
6763
个汉字,
682
个符号,所以确实有时候不是很够用。
GBK
一直能和
GB2312
相互混淆并且相安无事的一个重要原因是
GBK
全面兼容
GB2312
,所以没有出现任何冲突,你用
GB2312
编码的文件通过
GBK
去解释一定能获得相同的显示效果,换句话说:
GBK
对
GB2312
就是,你有的,我也有,你没得的,我还有!
好了,
ANSI
的标准是什么呢,首先是
ASCII
的代码你不能用!也就是说
ASCII
码在任何
ANSI
中应该都是相同的。其他的,你们自己扩展。所以呢,中国人就把
ASCII
码变成
8
位,
0x7f
之前我不动你的,我从
0xa0
开始编,
0xa0
到
0xff
才
95
个码位,对于中国字那简直是杯水车薪,因此,就用两个字节吧,因此编码范围就从
0xA1A1 - 0xFEFE
,这个范围可以表示
23901
个汉字。基本够用了吧,
GB2312
才
7000
多个呢!
GBK
更猛,编码范围是从
0x8140
- 0xFEFE,
可以表示
3
万多个汉字。可以看出,这两种方案,都能保证汉字头一个字节在
0x7f
以上,从而和
ASCII
不会发生冲突。能够实现英文和汉字同时显示。
BIG5
,香港和台湾用的比较多,繁体,范围:
0xA140 - 0xF9FE, 0xA1A1 - 0xF9FE
,每个字由两个字节组成,其第一
字节编码范围为
0xA1~0xF9
,第二字节编码范围为
0x40-0x7E
与
0xA1-0xFE
,总计收入
13868
个字
(
包括
5401
个常用字、
7652
个次常用字、
7
个扩充字、以及
808
个各式符号
)
。
那么到底
ANSI
是多少位呢?这个不一定!比如在
GB2312
和
GBK
,
BIG5
中,是两位!但是其他标准或者其他语言如果不够用,就完全可能不止两位!
例如:
GB18030:
GB18030-2000(GBK2K)
在
GBK
的基础上进一步扩展了汉字,增加了藏、蒙等少数民族的字形。
GBK2K
从根本上解决了字位不够,字形不足的问题。它有几个特点:它并没有确定所有的字形,只是规定了编码范围,留待以后扩充。编码是变长的,其二字节部分与
GBK
兼容;四字节部分是扩充的字形、字位,其编码范围是首字节
0x81-0xfe
、二字节
0x30-0x39
、三字节
0x81-0xfe
、四字节
0x30-0x39
。它的推广是分阶段的,首先要求实现的是能够完全映射到
Unicode3.0
标准的所有字形。它是国家标准,是强制性的。
搞懂了
ANSI
的含义,我们发现
ANSI
有个致命的缺陷,就是每个标准是各自为阵的,不保证能兼容。换句话说,要同时显示中文和日本文或者阿拉伯文,就完全可能会出现一个编码两个字符集里面都有对应,不知道该显示哪一个的问题,也就是编码重叠的问题。显然这样的方案不好,所以
Unicode
才会出现!
3.MBCS
(
Multi-Byte
Chactacter System
(
Set)
)
多字节字符系统或者字符集,基于
ANSI
编码的原理上,对一个字符的表示实际上无法确定他需要占用几个字节的,只能从编码本身来区分和解释。因此计算机在存储的时候,就是采用多字节存储的形式。也就是你需要几个字节我给你放几个字节,比如
A
我给你放一个字节,比如
"
中
“
,我就给你放两个字节,这样的字符表示形式就是
MBCS
。
在基于
GBK
的
windows
中,不会超过
2
个字节,所以
windows
这种表示形式有叫做
DBCS
(
Double-Byte
Chactacter System
),其实算是
MBCS
的一个特例。
C
语言默认存放字符串就是用的
MBCS
格式。从原理上来说,这样是非常经济的一种方式。
4.CodePage
代码页,最早来自
IBM
,后来被微软,
oracle
,SAP
等广泛采用。因为
ANSI
编码每个国家都不统一,不兼容,可能导致冲突,所以一个系统在处理文字的时候,必须要告诉计算机你的
ANSI
是哪个国家和地区的标准,这种国家和标准的代号(其实就是字符编码格式的代号),微软称为
Codepage
代码页,其实这个代码页和字符集编码的意思是一样的。告诉你代码页,本质就是告诉了你编码格式。但是不同厂家的代码页可能是完全不同,哪怕是同样的编码,比如,
UTF-8
字符编码
在
IBM
对应的代码页是
1208
,在微软对应的是
65001,
在德国的
SAP
公司对应的是
4110
。所以啊,其实本来就是一个东西,大家各自为政,搞那么多新名词,实在没必要!所以标准还是很重要的!!!
比如
GBK
的在微软的代码页是
936
,告诉你代码页是
936
其实和告诉你我编码格式是
GBK
效果完全相同。那么处理文本的时候就不会有问题,不会去考虑某个代码是显示的韩文还是中文,同样,日文和韩文的代码页就和中文不同,这样就可以
避免编码冲突导致计算机不知如何处理的问题。当然用这个也可以很容易的切换语言版本。
但是这都是治标不治本的方法,还是无法解决同时显示多种语言的问题,所以最后还是都用
unicode
吧,永远不会有冲突了。
5.Unicode(Universal
Code)
这是一个编码方案,说白了就是一张包含全世界所有文字的一个编码表,不管你用的上,用不上,不管是现在用的,还是以前用过的,只要这个世界上存在的文字符号,统统给你一个唯一的编码,这样就不可能有任何冲突了。不管你要同时显示任何文字,都没有问题。
因此在这样的方案下,
Unicode
出现了。
Unicode
编码范围是:
0-0x10FFFF
,可以容纳
1114112
个字符,
100
多万啊。全世界的字符根本用不完了,
Unicode 5.0
版本中,才用了
238605
个码位。所以足够了。
因此从码位范围看,严格的
unicode
需要
3
个字节来存储。但是考虑到理解性和计算机处理的方便性,理论上还是用
4
个字节来描述。
Unicode
采用的汉字相关编码用的是《
CJK
统一汉字编码字符集》
—
国家标准
GB13000.1
是完全等同于国际标准《通用多八位编码字符集
(UCS)
》
ISO 10646.1
。《
GB13000.1
》中最重要的也经常被采用的是其双字节形式的基本多文种平面。在这
65536
个码位的空间中,定义了几乎所有国家或地区的语言文字和符号。其中从
0x4E00
到
0x9FA5
的连续区域包含了
20902
个来自中国(包括台湾)、日本、韩国的汉字,称为
CJK (Chinese Japanese Korean)
汉字。
CJK
是《
GB2312-80
》、《
BIG5
》等字符集的超集。
CJK
包含了中国,日本,韩国,越南,香港,也就是
CJKVH
。这个在
UNICODE
的
Charset chart
中可以明显看到。
unicode
的相关标准可以从
unicode.org
上面获得,目前已经进行到了
6.0
版本。
下面这段描述来自百度百科:
Unicode
字符集可以简写为
UCS
(
Unicode Character Set
)。早期的
unicodeUnicode
标准有
UCS-2
、
UCS-4
的说法。
UCS-2
用两个字节编码,
UCS-4
用
4
个字节编码。
UCS-4
根据最高位为
0
的最高字节分成
2^7=128
个
group
。每个
group
再根据次高字节分为
256
个平面(
plane
)。每个平面根据第
3
个字节分为
256
行
(
row
),每行有
256
个码位(
cell
)。
group 0
的平面
0
被称作
BMP
(
Basic Multilingual Plane
)。将
UCS-4
的
BMP
去掉前面的两个零字节就得到了
UCS-2
。每个平面有
2^16=65536
个码位。
Unicode
计划使用了
17
个平面,一共有
17*65536=1114112
个码位。在
Unicode 5.0.0
版本中,已定义的码位只有
238605
个,分布在平面
0
、平面
1
、平面
2
、平面
14
、平面
15
、平面
16
。其中平面
15
和平面
16
上只是定义了两个各占
65534
个码位的专用区(
Private Use Area
),分别是
0xF0000-0xFFFFD
和
0x100000-0x10FFFD
。所谓专用区,就是保留给大家放自定义字符的区域,可以简写为
PUA
。
平面
0
也有一个专用区:
0xE000-0xF8FF
,有
6400
个码位。平面
0
的
0xD800-0xDFFF
,共
2048
个码位,是一个被称作代理区(
Surrogate
)的特殊区域。代理区的目的用两个
UTF-16
字符表示
BMP
以外的字符。在介绍
UTF-16
编码时会介绍。如前所述在
Unicode 5.0.0
版本中,
238605-65534*2-6400-2408=99089
。余下的
99089
个已定义码位分布在平面
0
、平面
1
、平面
2
和平面
14
上,它们对应着
Unicode
目前定义的
99089
个字符,其中包括
71226
个汉字。平面
0
、平面
1
、平面
2
和平面
14
上分别定义了
52080
、
3419
、
43253
和
337
个字符。平面
2
的
43253
个字符都是汉字。平面
0
上定义了
27973
个汉字。
6.Unicode
的实现方案
Unicode
其实只是一张巨大的编码表。要在计算机里面实现,也出现了几种不同的方案。也就是说如何表示
unicode
编码的问题。
UTF-8
(
UCS
Transformation Format 8bit)
这个方案的意思以
8
位为单位来标识文字,注意并不是说一个文字用
8
位标识。他其实是一种
MBCS
方案,可变字节的。到底需要几个字节表示一个符号,这个要根据这个符号的
unicode
编码来决定,最多
4
个字节。
编码规则如下:
Unicode
编码
(16
进制
)
║
UTF-8
字节流
(
二进制
)
000000 - 00007F
║
0xxxxxxx
000080 - 0007FF
║
110xxxxx 10xxxxxx
000800 - 00FFFF
║
1110xxxx 10xxxxxx
10xxxxxx
010000 - 10FFFF
║
11110xxx 10xxxxxx
10xxxxxx 10xxxxxx
UTF-8
的特点是对不同范围的字符使用不同长度的编码。对于
0x00-0x7F
之间的字符,
UTF-8
编码与
ASCII
编码完全相同。
UTF-8
编码的最大长度是
4
个字节。从上表可以看出,
4
字节模板有
21
个
x
,即可以容纳
21
位二进制数字。
Unicode
的最大码位
0x10FFFF
也只有
21
位。
例
1
:
“
汉
”
字的
Unicode
编码是
0x6C49
。
0x6C49
在
0x0800-0xFFFF
之间,使用用
3
字节模板了:
1110xxxx
10xxxxxx 10xxxxxx
。将
0x6C49
写成二进制是:
0110 1100 0100 1001
,
用这个比特流依次代替模板中的
x
,得到:
11100110 10110001 10001001
,即
E6 B1 89
。
例
2
:
Unicode
编码
0x20C30
在
0x010000-0x10FFFF
之间,使用用
4
字节模板了:
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
。
将
0x20C30
写成
21
位二进制数字(不足
21
位就在前面补
0
):
0 0010 0000
1100 0011 0000
,用这个比特流依次代替模板中的
x
,得到:
11110000 10100000 10110000 10110000
,即
F0 A0 B0 B0
。
(
2
)
UTF-16
UTF-16
编码以
16
位无符号整数为单位。注意是
16
位为一个单位,不表示一个字符就只有
16
位。现在机器上的
unicode
编码一般指的就是
UTF-16
。绝大部分
2
个字节就够了,但是不能绝对的说所有字符都是
2
个字节。这个要看字符的
unicode
编码处于什么范围而定,有可能是
2
个字节,也可能是
4
个字节。这点请注意!
下面算法解释来自百度百科。
我们把
Unicode
unicode
编码记作
U
。编码规则如下:
如果
U<0x10000
,
U
的
UTF-16
编码就是
U
对应的
16
位无符号整数(为书写简便,下文将
16
位无符号整数记作
WORD
)。
如果
U≥0x10000
,我们先计算
U'=U-0x10000
,然后将
U'
写成二进制形式:
yyyy
yyyy yyxx xxxx xxxx
,
U
的
UTF-16
编码(二进制)就是:
110110yyyyyyyyyy 110111xxxxxxxxxx
。为什么
U'
可以被写成
20
个二进制位?
Unicode
的最大码位是
0x10ffff
,减去
0x10000
后,
U'
的最大值是
0xfffff
,所以肯定可以用
20
个二进制位表示。
例如:
Unicode
编码
0x20C30
,减去
0x10000
后,得到
0x10C30
,写成二进制是:
0001 0000 1100 0011 0000
。用前
10
位依次替代模板中的
y
,用后
10
位依次替代模板中的
x
,就得到:
1101100001000011
1101110000110000
,即
0xD843
0xDC30
。
按照上述规则,
Unicode
编码
0x10000-0x10FFFF
的
UTF-16
编码有两个
WORD
,第一个
WORD
的高
6
位是
110110
,第二个
WORD
的高
6
位是
110111
。可见,第一个
WORD
的取值范围(二进制)是
11011000 00000000
到
11011011 11111111
,即
0xD800-0xDBFF
。第二个
WORD
的取值范围(二进制)是
11011100 00000000
到
11011111 11111111
,即
0xDC00-0xDFFF
。
为了将一个
WORD
的
UTF-16
编码与两个
WORD
的
UTF-16
编码区分开来,
Unicode
编码的设计者将
0xD800-0xDFFF
保留下来,并称为代理区(
Surrogate
):
D800
-
DB7F
║
High Surrogates
║
高位替代
DB80
-
DBFF
║
High Private Use
Surrogates
║
高位专用替代
DC00
-
DFFF
║
Low Surrogates
║
低位替代
高位替代就是指这个范围的码位是两个
WORD
的
UTF-16
编码的第一个
WORD
。低位替代就是指这个范围的码位是两个
WORD
的
UTF-16
编码的第二个
WORD
。那么,高位专用替代是什么意思?我们来解答这个问题,顺便看看怎么由
UTF-16
编码推导
Unicode
编码。
如果一个字符的
UTF-16
编码的第一个
WORD
在
0xDB80
到
0xDBFF
之间,那么它的
Unicode
编码在什么范围内?我们知道第二个
WORD
的取值范围是
0xDC00-0xDFFF
,所以这个字符的
UTF-16
编码范围应该是
0xDB80 0xDC00
到
0xDBFF 0xDFFF
。我们将这个范围写成二进制:
1101101110000000 11011100 00000000 - 1101101111111111
1101111111111111
按
照编码的相反步骤,取出高低
WORD
的后
10
位,并拼在一起,得到
1110 0000
0000 0000 0000 - 1111 1111 1111 1111 1111
即
0xe0000-0xfffff
,按照编码的相反步骤再加上
0x10000
,得到
0xf0000-0x10ffff
。这就是
UTF-16
编码的第一个
WORD
在
0xdb80
到
0xdbff
之间的
Unicode
编码范围,即平面
15
和平面
16
。因为
Unicode
标准将平面
15
和平面
16
都作为专用区,所以
0xDB80
到
0xDBFF
之间的保留码位被称作高位专用替代。
(
3
)
UTF-32
这个就简单了,和
Unicode
码表基本一一对应,固定四个字节。
为什么不采用
UTF-32
呢,因为
unicode
定义的范围太大了,其实
99%
的人使用的字符编码不会超过
2
个字节,所以如同统一用
4
个字节,简单倒是简单了,但是数据冗余确实太大了,不好,所以
16
位是最好的。就算遇到超过
16
位能表示的字符,我们也可以通过上面讲到的代理技术,采用
32
位标识,这样的方案是最好的。所以现在绝大部分机器实现
unicode
还是采用的
utf-16
的方案。当然也有
UTF-8
的方案。比如
windows
用的就是
UTF16
方案,不少
linux
用的就是
utf8
方案。
7.
编码存储差异
这里就要引出两个名词:
LE
(
little endian):
小字节字节序,意思就是一个单元在计算机中的存放时按照低位在前(低地址),高位在后(高地址)的模式存放。
BE
(
big endian):
大字节字节序,和
LE
相反,是高位在前,低位在后。
比如一个
unicode
编码为:
0x006C49
,如果是
LE
,那么在文件中的存放顺序应该是:
49 6c 00
如果是
BE ,
那么顺序应该是:
00 6c 49
8.
编码格式的检测
到底采用什么编码,如果能检测就好了。专家们也是这么想的,所以专家给每种格式和字节序规定了一些特殊的编码,
这些编码在
unicode
中是没有使用的,所以不用担心会冲突。
这个叫做
BOM
(
Byte Order
Mark
)头。意思是字节序标志头。通过它基本能确定编码格式和字节序。
UTF
编码
║
Byte Order Mark
UTF-8
║
EF BB BF
UTF-16LE
║
FF FE
UTF-16BE
║
FE FF
UTF-32LE
║
FF FE 00 00
UTF-32BE
║
00 00 FE FF
所以通过检测文件前面的
BOM
头,基本能确定编码格式和字节序。
但是这个
BOM
头只是建议添加,不是强制的,所以不少软件和系统没有添加这个
BOM
头(所以有些软件格式中有带
BOM
头和
NoBOM
头的选择),这个时候要检测什么格式,就比较麻烦了当然可以检测,但是不能保证
100%
准确,只能通过编码范围从概率上来检查,虽然准确度还是比较高,但是不能保证
100%
。所以,时常看到检测错误的软件,也不奇怪了。
总结:
终于写完了,其实这些问题都是不统一导致的,属于历史问题,所以才会有这些困惑,这里也呼吁所有的软件
开发人员自觉的采用
Unicode
标准进行文字处理,我相信在不久的将来,这些困扰都不会存在了,因为所有软件都是
unicode d ,
只要有字库,任何文字都能同时显示,也可以到任何语言的平台上的去运行,不再有乱码的困惑!其实现在绝大部分软件已经是这么做的了!
另外也不要被很多名词属于所迷惑,其实这些只是标准的问题,根本没有什么新的东西,更没有什么复杂的东西。
摘自
http://blog.csdn.net/softman11/archive/2011/01/08/6124345.aspx