字符编码

之前一直对字符编码比较懵懂,只是在平时工作中碰到乱码情况下才会接触到,并没有深入了解,现在深入认识一下(过程借鉴了hherima的博客和百度百科中的一些资料,在这里作为笔记记录)。

1、ASCII

美国人发明了计算机,首先会想到本国语言,即英文字符和一些控制字符和数字,共127个,用了七位二进制数来表示,这些成为ASCII码表,如图1。

后来用了第八位,即新增了128个,用来支持和补充ASCII之外的外来语字母或者图形符号,这些成为扩展ASCII码表,如图2。

图1:

图2:


2、GB2312

    聪明的中国人看到ASCII表之后,发现无法表示汉字。于是,就想到了继续扩展,但是要兼容之前的ASCII表。规定:一个小于127的字符表示的含义和以前一样,即ASCII表中内容,而两个大于127的字节连在一起,就表示一个汉字。前面一个字节(称为高字节)从0xA1到0xF7,后面一个字节(低字节)从0xA1到0xFE,这样就可以组合出近8000多个简体汉字了。

    GB2312还可以把数字符号,罗马希腊字母以及日本假名都编进去,连ASCII里本来就有的标点以及数字和字母重新编了两个字节长的编码,这就是常说的“全角”字符,而原来的127号以下的那些叫“半角”字符。

这种汉字方案就叫做“GB2312”,GB2312是对ASCII的中文扩展。


3、GBK

中国人发明了GB2312之后,用了一段时间,发现这些编码仍然不能全部包含所有汉字,于是将GB2312中没用到的码位都找出来用了。最后还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面是不是ASCII字符集里的内容。结果扩展完了之后的编码成为"GBK"标准。GBK中包含了GB2312的所有内容,同时又增加了近20000个新的汉字,包括繁体字和一些符号。

图3列出GBK的编码范围:


4、Unicode

中国创建了GBK的字符集用于中国使用,其他国家也纷纷创建自己国家的字符集,于是百家争鸣,互相之间交流带来极大障碍。这时候出现了新的编码方式,Unicode编码,欲将所有编码统一,所以规定了现存的各个国家和文明的每个字符对应的Unicode码。

Unicode,万国码,是基于通用字符集(Universal Character Set)的标准发展而来。它为每种语言的每个字符设定了统一且唯一的二进制编码,以满足语言、跨平台进行文本转换、处理的要求。

Unicode用数字0到0x10FFFF来映射这些数字,最多容纳1114112个字符。

5、UTF-8

UTF-8是Unicode的一种存储、传输方式。Unicode是一个标准,UTF-8是实现,是以字节为单位对Unicode进行编码。UTF-8是可变长的编码方式,如下图:


“汉”字的Unicode编码是0x6C49。0x6C49在0x0800-0xFFFF之间,使用用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将0x6C49写成二进制是:0110 1100 0100 1001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。


6、UTF-16

UTF-16编码以16位无符号整数为单位。我们把Unicode编码记作U。编码规则如下:

如果U<0x10000UUTF-16编码就是U对应的16位无符号整数(为书写简便,下文将16位无符号整数记作WORD)。

如果U≥0x10000,我们先计算U'=U-0x10000,然后将U'写成二进制形式:yyyy yyyy yyxxxxxx xxxxUUTF-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-0x10FFFFUTF-16编码有两个WORD,第一个WORD的高6位是110110,第二个WORD的高6位是110111。可见,第一个WORD的取值范围(二进制)是110110000000000011011011 11111111,即0xD800-0xDBFF。第二个WORD的取值范围(二进制)是11011100 0000000011011111 11111111,即0xDC00-0xDFFF


于是得到Unicode编码,用UTF-16编码结果的方式为:

0x10000 + (前导-0xD800) * 0x400 + (后导-0xDC00) = utf-16编码。

其中,Unicode的前两个字节和后两个字节分别为前导和后导,也称为代理对。代理对是Unicode专门预留的一个代理区域,不表示任何字符。

  1. if(Unicode第一个字节 >=0xD8 && Unicode <=0xDB){  
  2.     //这是代理区域,表示第1——16平面的字符。每四个字节表示一个单元  
  3. }  
  4. else{  
  5.     //这是正常映射区域,表示第0个平面。每两个字节表示一个单元。  
  6. }

这样的结果是:根据这个协议判断,计算机可以知道两个字节,还是四个自己表示一个字符。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值