大家好,欢迎来到IT知识分享网。
前言
一开始人类的世界只有电路的通断和电位的高低,后来有一群人,他们将电位的变化进行组合,构成了更加复杂,更多变化的电路,人们联想到这种电路的其中一种组合不正好可以表示一种状态,那么规定其中一种状态为一个数字,正好就可以进行数学运算,于是经过电路设计和实验,出现了加法运算器、减法运算器、乘法运算器、除法运算器等等等。再后来,有一群人他们将8个电位进行组合,构成了用来表示某种状态的基本单元,称之为“字节”。随着发展,出现了集数学运算和存储表示为一体的机器“计算机”。
计算机的本质是一种状态机,其本身不能直接表示现实世界的任何东西,所有现实世界的东西要想在计算机内部进行表示,就必须建立自身与计算机内部的状态的映射关系,而编码正好就是建立这种映射关系的一种方式。
一、字符集
字符集是对一些字符的集合,其规定了字符的码值,码值=计算机内部的表示状态。如ascii码,其包含了所有的英文字母的计算机内部表示,也包含一些特殊符号的表示。GBK则包含一些中文字符的计算机内部表示。UNICODE其包含了全世界大多数的字符的计算机内部表示,是一个非常大的集合。
二、编码格式
编码格式是字符的码值在计算机内部具体的实现方式,其定义了一个字符的码值在计算机内应该如何存储。
三、一些字符集及其编码格式
1、ASCII码
ASCII是美国标准信息交换码,其包含了所有的英文字母和一些特殊字符的码值的规定。同时该字符集也规定了码值在计算机内部的存储方式,即单字节存储。
2、ASCI
ASCI字符集是兼容了ASCII码的各国自己实现的一种字符集。
美国国家标准协会,也就是说,每个国家(非拉丁语系国家)自己制定自己的文字的编码规则,并得到了ANSI认可,符合ANSI的标准,全世界在表示对应国家文字的时候都通用这种编码就叫ANSI编码。换句话说,中国的ANSI编码和在日本的ANSI的意思是不一样的,因为都代表自己国家的文字编码标准。比如中国的ANSI对应就是GB2312标准,日本就是JIT标准,香港,台湾对应的是BIG5标准等等。当然这个问题也比较复杂,微软从95开始,用就是自己搞的一个标准GBK。GBK兼容了GB2312。
同时每一个ASCI字符集都有对应的自己的计算机内部的编码格式,即计算机内部的表示的实现方式。
GB2312最常见的编码格式就是ECU_CN。
GBK则采用的是双字节的表示方法。这两种字符集都直接定义了字符的编码同时也定义了编码格式,即直接采用双字节的编码格式。
3、unicode
这是一个编码方案,说白了就是一张包含全世界所有文字的一个编码表,不管你用的上,用不上,不管是现在用的,还是以前用过的,只要这个世界上存在的文字符号,统统给你一个唯一的编码,这样就不可能有任何冲突了。不管你要同时显示任何文字,都没有问题。因此在这样的方案下,Unicode出现了。Unicode编码范围是:0-0x10FFFF,可以容纳个字符,100多万啊。全世界的字符根本用不完了,Unicode 5.0版本中,才用了个码位。所以足够了。
因此从码位范围看,严格的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的Charsetchart中可以明显看到。 unicode的相关标准可以从unicode.org上面获得,目前已经进行到了6.0版本。
目前unicode的编码格式主要有以下三种:
(1)、utf-8
这个方案的意思以8位为单位来标识文字,注意并不是说一个文字用8位标识。他其实是一种MBCS方案,可变字节的。到底需要几个字节表示一个符号,这个要根据这个符号的unicode编码来决定,最多4个字节。 目前这种方案已经成为RFC3629标准。
编码规则如下:
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,得到: ,即E6 B1 89。
例2:Unicode编码0x20C30在0x010000-0x10FFFF之间,使用用4字节模板了:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx。
将0x20C30写成21位二进制数字(不足21位就在前面补0):0 00 1100 0011 0000,用这个比特流依次代替模板中的x,得到: ,即F0 A0B0 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编码(二进制)就是:yyyyyyyyyyxxxxxxxxxx。为什么U’可以被写成20个二进制位?Unicode的最大码位是0x10ffff,减去0x10000后,U’的最大值是0xfffff,所以肯定可以用20个二进制位表示。
例如:Unicode编码0x20C30,减去0x10000后,得到0x10C30,写成二进制是:0001 0000 1100 0011 0000。用前10位依次替代模板中的y,用后10位依次替代模板中的x,就得到:00011 10000,即0xD8430xDC30。
按照上述规则,Unicode编码0x10000-0x10FFFF的UTF-16编码有两个WORD,第一个WORD的高6位是,第二个WORD的高6位是。可见,第一个WORD的取值范围(二进制)是 00000000到 ,即0xD800-0xDBFF。第二个WORD的取值范围(二进制)是 00000000到 ,即0xDC00-0xDFFF。为了将一个WORD的UTF-16编码与两个WORD的UTF-16编码区分开来,Unicode编码的设计者将0xD800-0xDFFF保留下来,并称为代理区(Surrogate):
D800-DB7F ║ High Surrogates ║ 高位替代
DB80-DBFF ║ High PrivateUse Surrogates ║ 高位专用替代
DC00-DFFF ║ LowSurrogates ║ 低位替代
高位替代就是指这个范围的码位是两个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。我们将这个范围写成二进制: 00000 00000000 – 按照编码的相反步骤,取出高低WORD的后10位,并拼在一起,得到 1110 0000 0000 0000 0000 -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方案。
由于一种字符集有多种编码格式,所以就出现了编码格式检测的问题。
编码格式的检测
到底采用什么编码,如果能检测就好了。专家们也是这么想的,所以专家给每种格式和字节序规定了一些特殊的编码,这些编码在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,这样也方便了程序的国际化,只要有字库,则就能很好的显示。
在传输的过程中最好使用utf-8,那样就保证了传输之后的正确性。
最后附录几个概念:
CodePage:代码页,最早来自IBM,后来被微软,oracle,SAP等广泛采用。因为ANSI编码每个国家都不统一,不兼容,可能导致冲突,所以一个系统在处理文字的时候,必须要告诉计算机你的ANSI是哪个国家和地区的标准,这种国家和标准的代号(其实就是字符编码格式的代号),微软称为Codepage代码页,其实这个代码页和字符集编码的意思是一样的。
MBCS:多字节字符系统或者字符集
UTF:Unicode Transformation Format,unicode转换格式
BOM : Byte Order Mark字节序标志头,通过它基本能确定编码格式和字节序。
附上小故事一则:
记事本里面“联通”,然后保存,再次打开,则无法显示。
原因:当我们在输入“联通”这两个字的时候,我们采用的是GB系列的编码方式,但是保存的时候发生了误会,默认采用ASCI,也就是采用了相应字符集的编码格式,即采用了GB系列的编码格式。“联通”的内码是: c1 1100 0001 aa 1010 1010 cd 1100 1101 a8 1010 1000 第一二个字节、第三四个字节的起始部分的都是”110″和”10″,正好与UTF8规则里的两字节模板是一致的,于是再次打开记事本时,记事本就误认为这是一个UTF8编码的文件,让我们把第一个字节的110和第二个字节的10去掉,我们就得到了”00001 “,再把各位对齐,补上前导的0,就得到了”0000 0000 0110 1010″,不好意思,这是UNICODE的006A,也就是小写的字母”j”,而之后的两字节用UTF8解码之后是0368,这个字符什么也不是。这就是只有”联通”两个字的文件没有办法在记事本里正常显示的原因。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/149281.html