字符编码问题
博客园处女座,献给烦人的字符编码。
我们经常会被编码的问题所困扰,之所以被困扰是因为编码的种类有多种,在需要转换的时候就会出现各种问题,因此如若要不困惑,首先我们必须抽丝剥茧,把以下几个问题捋清楚,让问题没有死角,就可以游刃有余了。
一、字符编码的种类有几种。
ASCII编码、GB2312编码、Unicode编码、UTF-8编码
二、这几种字符编码的长度。
ASCII编码:一个字节
GB2312编码:两个字节
Unicode编码:通常是2个字节(注意通常二字,Unicode的编码长度标准不一,UCS-2用两个字节编码,UCS-4用4个字节编码。为什么会这样?因为有些非常偏僻的字符需要四个字节的长度。这点没什么大用,不需要细究)
UTF-8编码:1-6个字节。utf-8又叫可变长编码,为什么这么设计,后面讲到。
三、编码的作用。
现在我们反过来研究一下深层的东西,理解一下编码的产生及作用。
编码是干嘛用的? 计算机的发明是人类文明历史上最伟大的发明之一,而这项发明的灵魂莫过于0和1即二进制。也就是说计算机是用二级制来模拟一切的,小到计算1+1=2大到大型游戏的运作,计算机在底层所处理的都是有0和1而已。并且计算机能处理的也只有数字。那当我们遇到英文中文法语等这种字符串时,改怎么让计算机处理呢?这时候就需要用到编码,把这些非数字转化成计算机认识的数字,比如我们用ASCII编码将英文的A编成65(注意这里用的是十进制来表示,计算机里用的当然是二进制,即为01000001)。这里的ASCII编码即为编码的一种,它和其它编码一样解决的都是把计算机不认识的非数字转化成数字的一种规则而已。
四、不同编码产生的原因。
1、ASCII编码。计算机是美国人发明的,所以ASCII编码是最早的一种编码格式,用来把他们常用的字符编码成数字。其英文全名是American Standard Code for Information Interchange。最早只有127个字母被编码到计算机里,其中包含大小写英文字母、数字和一些符号。现在最多可以表示256种字符。由此可见,ASCII在编码的时候并没有考虑到中文、日文等其他语言编码的问题。所以,当需要把中文编码的时候用ASCII编码就不能用了。
2、GB2312编码。因为ASCII码表示不了中文所以在中国人发明了gb2312,gb2312也不是随便就能发明的,首先得不能和ASCII码冲突,因为计算机的底层已经打上英文的烙印了(美国生出来的东西,肯定是姓美国的),其次要考虑编码长度的问题,由于一个字节最多表示256种字符,所以要编码就得至少两个字节,两个字节可以表示65535种字符(注意这里面包含了已经被ASCII占用的那些)。同理,日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里。那么问题又来了,既然每个国家都有自己的编码规则,那么当在一个多语言环境下就会出现冲突,你中国告诉我把20013(十进制)编程“中”字,韩国告诉我把20013编成“습니다”,我(计算机)就不明白20013是什么意思了,所以造成乱码。问题出现了,但是解决办法似乎也呼之欲出了,再定一个包含所有国家的标准呗。
3、Unicode编码。所谓时势造英雄,Unicode应运而生。Unicode把所有语言都编进去了,这样就不会再有乱码问题了。这样是不是就天下太平,共享盛世了?答案是发展总是被需要的。当一个问题被解决后,别的问题就会进入视野,嗷嗷待哺被解决。那么Unicode编码有什么问题呢。且往下看。
4、utf-8编码。一种情景:现在我们采用Unicode编码来编码一篇英文文章,这篇文章一共100个字母,那我们需要多大的空间来存储呢,100*2=200个字节。我们能不能用ASCII编码来编码呢,答案是of course, it's all of English. man~“ASCII需要多少空间呢?100*1=100个字节。所以可见,用Unicode来编一篇英文文章是浪费空间的。那么根据这个现象我们来反思,Unicode在编码的时候是否造成了空间浪费呢,答案是肯定的。所以utf-8就在Unicode的基础上完成了进化,即”可变长编码“。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间了。
5、编码现状。既然utf-8全面又节俭,是不是就可以一统天下了呢,答案是然而并没有。现实情况是:在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码(原因待查明)。另外UTF-8编码有一个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的一部分,所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。
五、Java解决乱码常用招数。
java常见乱码是java web中 前端与后端编码方式不同造成的,比如前端用了gb2312而后端用了utf-8就会造成乱码问题。
解决办法显而易见,让两端的编码方式相同即可。具体操作,环境不同,方法不同,需要具体问题具体分析。大概有以下两种:
1、前端不变,后台转码
如果你知道了前台页面的编码比如用的是iso8859-1(西欧语言编码),而后台用的是GBK,那在后台可以这样处理:
String str= new String(req.getParameter("str").toString().getBytes("iso8859_1"), "GBK");
为什么会拿iso8895-1举例呢,相信广大程序员也一定言犹在耳恍若昨日吧,那是因为当你的servlet容器使用Tomcat的时候,对于GET请求用request.setCharacterEncoding方法设置编码是不起作用的,tomcat会永远使用iso-8859-1编码,所以tomcat将会使用iso-8859-1将提交的字节转换成字符串,即你在后台拿到的就是iso8859-1编码的字符了,如果这个字符是中文,那恭喜你你看到的就是乱码了。
2、前后端一起处理,即前端用URL编码,后端解码。
前端解码使用js的encodeURI()进行统一的编码。
后端解码使用java.net.URLDecoder.decode(str, "UTF-8");
这里为什么用UTF-8呢 因为js引擎内码是unicode,所以通过encodeURI(str)进行URL编码的时候均属utf8编码
以上是两种常见的解决办法,其实乱码问题的海洋浩瀚无穷,更多乱码问题,敬请期待。。。

浙公网安备 33010602011771号