在计算机中,全部的数据只多是0或者1(用高电平和低电平分别表示1和0),那么咱们一般看到的字符也就只能用0和1来表示呀。因而科学家们(这里指的是美国的科学家)就想出一个办法,把一个特定的数字对应一个特定的字母进行存储和传输,好比我须要存储字母a,那么我存入一个数字97(即在计算机中存入二进制(01100001),这个过程叫作编码(encode),而咱们在读取数据的时候,当遇到97时,咱们就让计算机显示字母a,这个过程叫作解码(decode)。
为了你们在数据传输的时候不至于产生误会,那么咱们须要让全部的人都使用数字97来表明字母a,因此须要制定一份标准(即码表),最开始的这个标准叫作ASCII码表。
规则html
等等,咱们的中文字呢?
美国的"砖家"没有考虑那么久远呢!这就是后面出现那么多问题的根源所在啊。
实现方式
第一位始终未0,后面7位表示0-127的范围,一个数字对应一个字母或者标点符号,亦或者控制符号,即全部的ASCII码的统一形式为0xxxx xxxx。python
计算机技术到了欧洲,欧洲人发现怎么咱们的那么多符号没有编进去啊!
因此欧洲"砖家"坐到了一块儿,开始讨论。
发现既然美国人把第一位流出来了,那么咱们就用128-255的位置好了。
规则
128-159之间为控制字符,160-255位文字符号,其中包括了西欧语言、希腊语、泰语、阿拉伯语、希伯来语。
恰好把美国人给的空间所有用完,世界真美好,谢谢美利坚预留的每个位置。
砖家们决定把他们的编码名称叫作Latin1,后面因为欧洲统一制定ISO标准,因此又有了一个ISO的名称,即ISO-8859-1。
实现方式linux
计算机技术固然也传到了亚洲大地,好比中国。
中国砖家们坐在一块儿发现,美国人搞的这个东西真的有问题,预留才128-255的空间,但是咱们的汉字个数远远超出了这个数目啊,怎么办??
后面聪明的中国砖家们发现,只能使用2个字节了,不然真的搞不定。
因为必须和美国原来制定的ASCII不冲突,因此指定了以下规则
规则windows
后来,中国砖家们发现,不少的不经常使用汉字没有在码表中,因而添加了不少的汉字进去,这个编码叫作GBK,实现方式和GB2312是彻底同样的,兼容GB2312,固然也兼容ASCII。
实现方式服务器
后面再次添加更多的字符进去,再次命名为GB18030,兼容GBK。因为汉字不少,2个字节并不能彻底包括进去,因此GB18030采用2\4位混编的形式。ide
固然计算机也传到了日本(JIS)、韩国、台湾(BIG5)等等地方,你们所有发挥本身的聪明才智,各自实现了本身的编码。这些编码都与ASCII兼容,可是相互之间不兼容。ui
使用 2 个字节来表明一个字符的各类汉字延伸编码方式,称为 ANSI 编码,又称为"MBCS(Muilti-Bytes Charecter Set,多字节字符集)"。在简体中文系统下,ANSI 编码表明 GB2312 编码,在日文操做系统下,ANSI 编码表明 JIS 编码,因此在中文 windows下要转码成gb2312,gbk只须要把文本保存为ANSI编码便可。 不一样ANSI编码之间互不兼容编码
随着通信愈来愈多,而老美发如今本身公司须要国际化的时候,本身原来埋的这个雷真的害了本身。
因而乎,开始研讨把世界上几乎全部文字所有放在一个码表中,而这个一应俱全的码表就叫作Unicode,即万国码。
Unicode是国际组织制定的能够容纳世界上全部文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多能够容纳1114112个字符,或者说有1114112个码位。码位就是能够分配给字符的数字。
实际上,在软件制造商的协会(unicode.org)在作这个工做时,国际标准化组织(ISO)在作一样的事情,最后你们都意识到世界上并不须要两个不一样的万国码,因而你们坐在一块儿合并研究的成果,最后的结果就是如今的Unicode。操作系统
编码范围00-7F,其中00-1F、FF为控制字符。其它为英文字母、数字、标点符号。.net
编码范围00-FF,其中00-7F同ASCII,80-9F为控制符、9F-FF为字母和标点符号.
微软的企业标准,补充了一些符号和欧元符号,为Latin1的超集。
编码范围为A1A1-F7FE(剔除xx7F),共23940个码位。其中不少区间没有用到,而汉字使用的区间为B0A1-F7FE,其余为标点符号和特殊字符。
除经常使用简体汉字字符外还包括希腊字母、日文平假名及片假名字母、俄语西里尔字母等字符,未收录繁体中文汉字和一些生僻字。
对汉字进行了分区管理,其中第一个字节为区位码,包括下面区位。
01-09区为特殊符号。
16-55区为一级汉字,按拼音排序。
56-87区为二级汉字,按部首/笔画排序。
10-15区及88-94区则未有编码。
第二个字节为位字节,01-94总计94个。
为何实际选择不是01-5E,而是选择A1-F7的位置呢?
由于英文可见字符区间为20-7F,加上128(也就是最高位为1)后获得的取件便是A1-FE
区位码使用了0xA1-0xF7(把01-87区的区号加上0xA0),位字节使用了0xA1-0xFE(把01-94加上 0xA0)
编码范围为8140-FEFE,兼容GB2312,仍然有部分区间没有用到。
GBK也支持希腊字母、日文假名字母、俄语字母等字符,但不支持韩语中的表音字符(非汉字字符)。GBK还收录了GB2312不包含的 汉字部首符号、竖排标点符号等字符。
CP936是微软指定的标准,属于企业标准,和GBK的有些许差异,绝大多数状况下能够把CP936看成GBK的别名。
Big5是双字节编码,高字节编码范围是0x81-0xFE,低字节编码范围是0x40-0x7E和0xA1-0xFE。和GBK相比,少了低字节是0x80-0xA0的组合。0x8140-0xA0FE是保留区域,用于用户造字区。
Big5收录的汉字只包括繁体汉字,不包括简体汉字,一些生僻的汉字也没有收录。
微软的企业标准,能够理解为是对 Big5的扩展。
编码范围同GBK,补充了更多的字符,因为Unicode开始流行且GB18030补充的字符都比较生僻,因此实际使用上基本是GBK。
GB18030编码是变长编码,有单字节、双字节和四字节三种方式。GB18030的单字节编码范围是0x00-0x7F,彻底等同与ASCII;双字节编码的范围和GBK相同,高字节是0x81-0xFE,低字节的编 码范围是0x40-0x7E和0x80-FE;四字节编码中第1、三字节的编码范围是0x81-0xFE,2、四字节是0x30-0x39。
中文的编码范围为4E00-9FCF,其中9FC4-9FCF之间的区间没有使用。
一个蛋疼的问题就是这个区间所有都是文字,中文标点没有包含在其中,中文标点散落在各个位置。详细请看http://blog.chinaunix.net/uid-12348673-id-3335307.html。
一些特殊的文字和中文部首以及一些特殊符号也不在此范围内,详细状况能够参考网址:http://www.cnblogs.com/sosoft/p/3456631.html
大尾和小尾是CPU处理多字节数的不一样方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,到底是将6C写在前面,仍是将49写在前面?若是将6C写在前面,就是big endian。仍是将49写在前面,就是little endian。
UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每一个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。若是咱们收到UTF-16字节流“594E”,那么这是“奎”仍是“乙”?
Unicode规范中推荐的标记字节顺序的方法是BOM,即Byte Order Mark。BOM是一个有点小聪明的想法:
在UCS编码中有一个叫作"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,因此不该该出如今实际传输中。UCS规范建议咱们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。
这样若是接收者收到FEFF,就代表这个字节流是Big-Endian的;若是收到FFFE,就代表这个字节流是Little-Endian的。所以字符"ZERO WIDTH NO-BREAK SPACE"又被称做BOM。
UTF-8不须要BOM来代表字节顺序,但能够用BOM来代表编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF(读者能够用咱们前面介绍的编码方法验证一下)。因此若是接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。
Unicode只是进行了编码,也就是说只是一个码表,至于具体怎么实现,并无规定。
下面是Unicode的几种实现方法。
范围 | 字节数 | 存储格式 |
---|---|---|
0x0000~0x007F (0 ~ 127) | 1字节 | 0xxxxxxx |
0x0080~0x07FF(128 ~ 2047) | 2字节 | 110xxxxx 10xxxxxx |
0x0800~FFFF(2048 ~ 65535) | 3字节 | 1110xxxx 10xxxxxx 10xxxxxx |
0x10000~1FFFFFF(65536 ~ 2097152) | 4字节 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
0x2000000~0x3FFFFFF | 5字节 | 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
0x4000000~0x7FFFFFFF) | 6字节 | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
理论上说,UTF-8并无大小尾的困扰,因此并不须要BOM。
可是一些Windows应用会指定大小尾,好比Notepad,并且Excel在没有指定BOM的UTF-8文件进行读取时会使用Windows的codepage,从而出现错误。
在Unicode基本多文种平面定义的字符(不管是拉丁字母、汉字或其余文字或符号),一概使用2字节储存。而在辅助平面定义的字符,会以代理对(surrogate pair)的形式,以两个2字节的值来储存。
UTF-16比起UTF-8,好处在于大部分字符都以固定长度的字节 (2字节) 储存,但UTF-16却没法兼容于ASCII编码。
能够认为UTF-16是下面介绍的UCS-2的父集。在没有辅助平面字符(surrogate code points)前,UTF-16与UCS-2所指的是同一的意思。但当引入辅助平面字符后,就称为UTF-16了。如今如有软件声称本身支援UCS-2编码,那实际上是暗指它不能支援在UTF-16中超过2bytes的字集。对于小于0x10000的UCS码,UTF-16编码就等于UCS码。
若是一个UTF-16文件没有指定BOM,默认应该是UTF-16BE,可是在Intel x86中倒是UTF-16LE。因此在现实世界中有不少的没有指定大小尾的UTF-16倒是UTF-16LE。
每个Unicode码位使用刚好32位元。能够粗暴的认为UTF-32和下面要介绍的UCS-4是等同的。
采用2个字节,定长的表示每个字符,因此总计能够表示2^16个字符。
UCS-4根据最高位为0的最高字节分红2^7=128个group。每一个group再根据次高字节分为256个plane。每一个plane根据第3个字节分为256行(rows),每行包含256个cells。固然同一行的cells只是最后一个字节不一样,其他都相同。
group 0的plane 0被称做Basic Multilingual Plane, 即BMP。或者说UCS-4中,高两个字节为0的码位被称做BMP。
将UCS-4的BMP去掉前面的两个零字节就获得了UCS-2。在UCS-2的两个字节前加上两个零字节,就获得了UCS-4的BMP。而目前的UCS-4规范中尚未任何字符被分配在BMP以外。
请参考
字符编码之UCS-2与Utf-8
UCS-2和UTF-8的互相转换
从Windows2K开始,Win的系统内核开始彻底支持并彻底应用Unicode编写,全部ANSI字符在进入底层前,都会被相应的API转换成Unicode。
Linux 服务器上 UCS-2 编码方式与 Winodws 不一致,如下是有关两个平台 UCS-2 编码的潜规则:
对于JAVA/.NET/Python等这些“新”的语言来讲,内置的字符串所使用的字符集已经彻底是Unicode最重要的是,世界上大多数程序用的字符集都是Unicode,由于Unicode有利于程序国际化和标准化。
我会接着写另一篇文章。
参考资料