经过计算机编码的诞生和发展历程,理解为毛有这么多种字符编码,以及他们之间的区别。本文主要参考网页编码就是那点事,并进行适当修改。html
最先的时候,是在学习C语言的时候接触的ASCII编码(American Standard Code for Information Interchange,美国信息交换标准代码),知道是一种使用二进制(一个字节表示一个字符,8bit)来表示计算机的一些控制字符、通讯字符、大小写英文字符、阿拉伯数字以及一些标点运算等符号。因为是美国人制定的规则,当时只考虑了英语体系用到的一些符号(自私自利的美帝国主义,手动滑稽)。这种方案在当时计算机刚出现不久还能凑合使用,而且当时的存储成本也比较高,使用一个字节来存储也节省不少存储资源,同时也提升了传输效率。因为计算机技术发展迅猛,很快欧洲、中国、日本也开始开展本身的计算机研究。这时你们发现WTF,计算机不认识本身的母语呀,这怎么能行,计算机也文化歧视?各个国家开始搞事情了。java
首先发难的是欧美拉丁系国家,他们发现ASCII编码只用了从0000 0000(二进制)到0111 1111(二进制)128种符号,浪费啊浪费。他们决定采用127号以后的空位来表示这些新的字母、符号,还加入了不少画表格时须要用下到的横线、竖线、交叉等形状,一直把序号编到了最后一个状态255。从128到255这一页的字符集被称"扩展字符集",也就是Latin-1字符集,即ISO-8859-1。tomcat
这下欧美发达国家是够用了,可是老美没想到第三世界的国家也须要使用计算机吧。勤劳智慧的中国人民说,“这都不是事儿”。咱们发扬"拿来主义"精神,取其精华,去其糟粕。把ASCII编码的127位及以前的字符保留着,127位以后的那些乱七八糟的字符统统干掉。而且规定:一个汉字使用两个字节表示。,一个小于127的字符的意义与原来相同,但两个大于127的字符连在一块儿时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE。一共收录6763个汉字,其中一级汉字3755个,二级汉字3008个;同时收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682个字符。两个字节长的就是"全角"字符,而原来在127号如下的那些就叫"半角"字符了。
这种字符方案叫作GB 2312字符集,已经将常见的使用频率较高的一些汉字收录进去,基本可以知足绝大多数中国人民使用啦。服务器
But,要知道中国文化博大精深,还有不少生僻字没有办法使用,万一恰好是某个领导的名字呢(手动尴尬)。因而干脆再也不要求低字节必定是127号以后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,无论后面跟的是否是扩展字符集里的内容。结果扩展以后的编码方案被称为 GBK 标准。GBK兼容了GB 2312的全部内容,同时又增长了近20000个新的汉字(包括繁体字)和符号。网络
但还要团结少数民族呀,因而又提出了GB 18030,除保留所有GBK编码汉字,在第二字节把能使用范围再度进行扩展,增长了大约一百个汉字及四位元组编码空间,将GBK做为子集所有保留。架构
因为这些汉字编码标准都是采用两个字节表示一个汉字,统称为"DBCS"(Double Byte Charecter Set 双字节字符集)。所以开发人员在做中文处理的时候,常常要念一句咒语:"一个汉字算两个英文字符!一个汉字算两个英文字符……" 只有通过咒语加持的代码才能正常运行。post
但是中国大陆用的是简体字呀,虽然GBK已支持繁体字,当时台湾、香港、澳门等繁体中文通行区的人民特立独行,本身搞了一套Big5编码。还有其余国家的也各自为政,韩文编码EUC_KR字符集,日文编码Shift_JIS字符集,俄文编码KOI8-R字符集等等。书不一样文,这简直是阻碍人类文明在计算机世界的发展啊。学习
为告终束这种乱象,这时ISO(国际标准化组织)站出来了,他们绝对为世界650种语言进行统一编码。通过研究,终于整了一个Unicode字符集出来。因为当时计算机的存储器容量极大地发展了,空间不再成为问题了。因而 ISO 就直接规定必须用两个字节,也就是16位来统一表示全部的字符,对于ascii里的那些“半角”字符,Unicode 包持其原编码不变,只是将其长度由原来的8位扩展为16位,而其余文化和语言的字符则所有从新统一编码。因为"半角"英文符号只须要用到低8位,因此其高8位永远是0,所以这种大气的方案在保存英文文本时会多浪费一倍的空间。 并且原来的不少程序在计算字符串长度也不许确了,一个中文和一个英文都是一个字符!此外,Unicode它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储,以及如何进行传输。因为这些局限,致使Unicode只能是一种理论上的标准。编码
随着互联网的兴起,面向传输的众多 UTF(Unicode Transformation Format)标准出现了,UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。其余实现方式还包括 UTF-16(字符用两个字节或四个字节表示)和 UTF-32(字符用四个字节表示),不过在互联网上基本不用。画重点,这里的关系是,UTF-8 是 Unicode 的实现方式之一。UTF-8 最大的一个特色,就是它是一种变长的编码方式。它可使用1~4个字节表示一个符号,根据不一样的符号而变化字节长度。UTF-8编码规则:spa
对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。所以对于英语字母,UTF-8 编码和 ASCII 码是相同的。
对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一概设为10。剩下的没有说起的二进制位,所有为这个符号的 Unicode 码。
例如"汉"字的Unicode编码是6C49。6C49在0800-FFFF之间,因此要用3字节模板:1110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是:0110 1100 0100 1001,再依序替代模板中x,获得:1110-0110 10-110001 10-001001,即E6B189,这就是"汉"字的UTF-8编码。
使用UCS-2存储Unicode编码(也就是一个字符使用两个字节存储),因为计算机架构的不一样,好比,"汉"字,Unicode编码16进制,使用Big endian(大头方式)表示为6C49,使用Litter endian(小头方式)表示为496C。那么在网络传输及本地文件存储时,计算机怎么知道使用何种方式呢?Unicode 规范定义,每个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫作"零宽度非换行空格"(zero width no-break space),若是一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;若是头两个字节是FF FE,就表示该文件采用小头方式。
既然如今已经有了一个统一的UTF-8编码来表示全部语言来,为何如今不少程序以及系统仍旧还在使用GBK,Big5,ISO-8859-1等这些编码呢?我以为主要有两点因素:
对于Java以及tomcat遇到的一些编码问题,可参考深刻分析Java中的中文编码问题。该文章已经描述得十分透彻。在这里就简单说一下在Java编码中遇到中午乱码的几个处理方式:
对请求参数进行编码转换
String userName=request.getParamter("userName");
userName=new String(userName.getByte("iso-8859-1"),"utf-8");
对请求头进行编码转换
request.setCharacterEncoding("UTF-8");//该方法只对POST方式提交的数据有效,对GET方式提交的数据无效!
tomcat默认ISO-8859-1编码,对tomcat服务器server.xml文件设置编码,便可让tomcat以UTF-8的编码处理get请求。
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>