计算机中编码方式---ASCII,ISO-8859-1以及UTF-8和UTF-16编码

简介

在编程中经常会遇到的编码问题,例如乱码问题或者文本显示成??的形式.我们知道计算机是二进制的方式存储数据,要想将人类世界的文字和符号存储到计算机,就需要将数据”翻译”成计算机语言进行存储,显示的时候又”翻译”成人类可识的数据,那么中间是翻译的过程需要的”字典”就是编码表,也就是将计算机二进制和文字、符号映射.计算机中存储信息的最小单元是字节(byte),一个字节有8个二进制位(bit),每个二进制只有两种状态,0或者1表示.那么8个二进制位就是2的8次幂,结果是256种状态,二进制范围是从0000000011111111.

ASCII码

起初美国有关标准组织制定了一套编码叫ASCII码,用了一个字节低7位,最高位二进制位0,编码范围是00000000-0xxxxxxx,总共有128状态,表示了大小写字母,数字,标点符号以及特殊的控制字符.

0~31以及127(共33个)是控制字符,例如:LF(换行),CR(回车).

32~156(共95个)是字符,48~57为0到9共十个阿拉伯数字,65~122是大小的英文字母,其余的是字符,运算符等.

所以ACSII码编码的格式是0xxxxxxx.一个字节中除了ASCII编码外,剩余的位置还有128个状态,对于一些西欧国家,文字比较少,这些编码位置已经够用,但是对于汉字个数远多余128个,所以出现了其他编码方式.

ISO8859-1

别名是Latin1,Iso-8859-1编码是属于单字节的编码,即编码的范围是0到255.总共能表示256个字符,向下兼容了ACSII,也就是在ASCII编码的基础上扩展了127-255之间位置。编码范围是0x00-0xFF,涵盖了部分西欧的语言字符.由于和计算机的存储单元一样,应用比较广泛,例如在网络传输协议中和Mysql数据库默认的编码

GB2312

GB2312是中国国家标准总局在1980年发布,用于汉字处理,汉字通信等系统之间信息,主要编码的字符是简化汉字,以及常用字母和符号,*地区和新加坡等地广泛使用.总共收录字符有7445个,其中简化的汉字是6763,以及包含拉丁字母,希腊字母,日文平假名及片假名字母,俄语西里尔字母在内的全角字符有682个.

GB2312对收录的字符进行了分区处理,共有94个区,每个区有94个字符,这种表示字符的方式叫区位码.例如下面01区和02区. 

计算机中编码方式---ASCII,ISO-8859-1以及UTF-8和UTF-16编码

每个区具体的分布的字符如下:

区号

编码总数

表示的符号

01

94

一般符号

02

72

顺序号码

03

94

拉丁字母

04

83

日文假名

05

86

Katakana

06

48

希腊字母

07

66

俄文字母

08

63

汉语拼音符号

09

76

图形符号

10-15

0

没有编码

16-55

3755

一级汉字,以拼音为序

56-87

3008

二级汉字,以笔划为序

88-94

0

没有编码

     GB2312编码以两个字节来表示汉字和符号,第一个字节是区码,第二个字节是位码.由于GB2312编码覆盖了ACSII编码中字母和符号的编码,对于ASCII中的32个控制字符继续沿用,所以需要将编码移动十六进制20H(32)得到国标码,在计算机的存储中,使用GB2312编码和ASCII编码会出现冲突的情况,比如说,国标码是20H83H,但是ASCII编码中表示成字符是控制符”DC4”20H)和大写字母”S”(80H).如果遇到编码是2083H,解码成是汉字还是字符。容易引起歧义, 解决方式就是在计算机里面存储变形国标码,将区码和位码分别加上128,即每个字节的最高位将0改为1.

那么对于区位码.国标码和机内码转换的方式:

  1. 区位码(十六进制)+20 20H=国标码
  2. 国标码+80 80H=机内码

区位码转换成机内码,也可以直接区位码(十六进制)+A0A0H=机内码,

20208080等同A0A0的原因是20(十六进制)的十进制是32,80(十六进制)的十进制是128,32+128=160(十进制)->A0(十六进制).

也就是说GB2312编码是以2个字节进行存储的,存到到计算机里面的编码就是将GB2312区位码+A0 A0H=存储码(即机内码),此外计算机存储规则是此编码的补码,注意的是位码在前,区码在后面

GBK/GBK18030

GBK字符集是GB2312的扩展,兼容了GB2312字符编码,共包含了21886个字符,GBK也支持希腊字母,日文假名字母,俄语字母等.

GB18030编码向下兼容了GBKGB2312.GB18030收录了所有的Unicode3.1中的字符,包含中国少数民族的字符.编码方式变长编码,有单字节.双字节和四字节三种方式.GB18030的单字节编码范围是0x00-0x7F,完全等同于ASCII码;双字节编码的范围和GBK相同,高字节是0x81-0xFE,低字节的编 码范围是0x40-0x7E0x80-FE;四字节编码中第一、三字节的编码范围是0x81-0xFE,二、四字节是0x30-0x39

Unicode

     由于多种编码方式的存在,同一个二进制编码可以解释成不同的符号,解码如果和解码方式不要一致,可能出现乱码的情况。解决这种问题方式就是Unicode编码,Unicode是很大的字符集,可以理解成一部全世界上所有的文字和字符与数字对应的字典”, 容纳的字符达到了100多万,每一个字符对应一个数字,但对于具体怎么存储到计算机中没有任何规定.如果将Unicode编码存直接储到计算里面会有什么结果呢?例如汉字”,Unicode编码是0x4e2d,二进制是100111000101101,二进制数有15位,也就是最少要用两个字节表示.可以想象Unicode字符集越往后面的字符编码,需要三到四个字节,甚至更多的字节来存储.如果按照固定字节来存储,那么就需要按照数值最大的字符所需要的字节为标准,例如规定四个字节表示一个字符,那么像英文字母仅仅只需一个字节可以表示的字符(如字母”b”,二进制是1100010,只需要一个字节可表示),依旧需要四个字节表示,就会造成极大的空间浪费.

为了解决Unicode字符集在电脑中存储问题,出现了UTF-8UTF-16.UTF-32等编码方式.

需要注意的是UTF-8和UTF-16,UTF-32编码就是Unicode字符集存储到电脑中实现的方式,

UTF-8

 UTF-8编码是Unicode字符集一种编码方式,被广泛使用.特点是使用变长的字节数来存储数据, 一般都是14个字节,变长的方式指的是将Unicode编码按照规则进行编码,比如一个字节可表示所有的ASCII字符,就不需要用两个字节.

按照UTF-8编码规则,就是将Unicode字符集按照满足UTF-8编码规则存储,解码按照UTF-8编码规则进行解码.如下:

UTF-8占用字节数

Unicode 十六进制编码范围

UTF-8二进制编码方式

1个字节

0000 0000 - 0000 007F

0xxxxxxx

2个字节

0000 0080 - 0000 07FF

110xxxxx 10xxxxxx

3个字节

0000 0800 - 0000 FFFF

1110xxxx 10xxxxxx 10xxxxxx

4个字节

0001 0000 - 0010 FFFF

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

比如汉字”,Unicode的编码是0x4e2d(100111000101101),通过上面表对照可以知道,0x4e2d在Unicode十六进制编码0000 0800-0000 FFFF范围之间,那么UTF-8的编码方式应该时1110xxxx 10xxxxxx 10xxxxxx,填充方式就是将的二进制从后向前填充,多余的x使用0填充,那么UTF-8编码就是11100100 10111000 10101101,转换成十六进制就是E4B8AD

解码的过程也是根据UTF-8编码规则进行解码,首字节的第一位是0,那么就是一个字节对应一个字符,首字节前两位是11,那么就是两个字节表示一个字符,即有几个1,就用几个字节表示一个字符,比如”UTF-8编码就是11100100 10111000 10101101,首字节有3个1,就表示是三个字节表示一个字符,会根据1110xxxx 10xxxxxx 10xxxxxx拿到x的部分,100111000101101,十六进制是0x4e2d,Unicode字符集对应的就是汉字”.

变长编码的优点是节省空间,利于传输,适合字符串网络传输的编码方式。

UTF-16(没有辅助平面字符情况下等同UCS-2编码)

 UTF-16用定长2个字节或者是两个2个字节(代理对的形式表示)来编码Unicode字符,UTF-16编码比起UTF-8字节,大部分的字符都是以固定两个字节存储,但是无法兼容ASCII编码。先对Unicode字符集的平面需要了解。

Unicode字符集将世界上所有的文字和符号进行了编码,目前Unicode字符分成了17个组(区)来编排,总的编码范围是0x0000-0x10FFFF(十进制是1114112,即能容纳的字符这么多)。每一个组又称为一个平面,每个平面有65536个码位,即每个平面能容纳字符65536个字符。

第一个组,又称为第零平面或者基本平面(BMP,编码范围是0x0000-0xFFFF,所有常见的文字和字符都在这个平面,其他的组或者区叫辅助平面(SMP),编码的范围是0x10000-0x10FFFFUTF-16编码的规则是:基本平面内的字符用2个字节表示,而辅助平面的字符要用4个字节表示

在基本平面里面有个称为代理区的特殊区域,编码范围是0xD800-0xDFFF,共有2048个码位,此区间不对应任何字符,主要是用于映射辅助平面的字符。

UTF-16占用字节数

Unicode十六进制编码范围

UTF-16二进制编码方式

Unicode字符范围

2个字节

0x0000-0xFFFF

xxxxxxxx xxxxxxxx

0-65535

4个字节

0x10000-0x10FFFF

110110yyyyyyyyyy 110111xxxxxxxxxx

65536-1114111

具体编码如下:

  • 1.Unicode编码范围是0x0000-0xFFFF,即编码<0x10000,UTF-16编码与Uncode字符的值保持一致。比如汉字“”,Unicode十六进制是0x554A,是上表中Unicode十六进制编码0x0000-0xFFFF范围,UTF-16占用两个字节,是基本平面内的字符,UTF-16编码方式是0x554A(二进制是101010101001010

2.Unicode编码范围是0x10000-0x10FFFF,即编码>=0x10000.Unicode编码值是U,计算编码值=U-0x10000转换成二进制就是yyyyyyyyyy xxxxxxxxxx,其中二进制位不存在的补0.那么UTF-16编码就是110110yyyyyyyyyy 110111xxxxxxxxxx.

UTF-164个字节编码方式看,第一个2个字节,即110110yyyyyyyyyy,取值范围是1101100000000000-1101101111111111,转换成十六进制就是0xD800-0xDBFF,此区间称为高位替代。

对于Unicode编码范围大于0x10000的字符。第二个2个字节是110111xxxxxxxxxx,取值范围是1101110000000000-1101111111111111,转换成十六机制就是0xDC00-0xDFFF。此区间称为低位替代。

0xD800-0xDBFF

高位替代

0xDC00-0xDFFF

低位替代

      可以看到Unicode字符集中>0x10000的字符,也就是辅助平面内的字符,通过UTF-16编码规则将每两个字节映射到0xD800-0xDBFF之间,所以当一篇文档使用UTF-16编码,两个字节编码范围是0xD800-0xDBFF之间,说明解码需要前后四个字节才能解码出一个完整字符。

例如:汉字“