- 浏览: 248742 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
leibnitz:
有几点要请教下;a.在二阶段里有这样一句:引用例如如果一个 p ...
zookeeper源码学习 -
nettm:
不错,我也遇到了第一个问题
mongodb客户端错误集合 -
lingqi1818:
xiaoych 写道很好,研究了一年多了吧,哈哈 难得你上 ...
80x86系统启动原理 -
xiaoych:
很好,研究了一年多了吧,哈哈
80x86系统启动原理 -
pengpeng:
pengpeng 写道很强大。我觉得mas-slave那块可以 ...
分布式计算需求场景以及解决方案
这几天做一个项目,基本上前台都是通过AJAX请求过来的,前端设计师用了雅虎的yui框架来封装JS。由于我们的系统一直采用GBK字符集编码,但是前端yui却只能通过utf-8编码把数据传过来,因为没有权限去修改框架级别的代码,所以只好跟ui约定好,在传送的数据中加一个_inut_charest=utf-8的参数,然后我在程序里恶心的硬编码进行convert。代码如下:
很顺利的就调试通过了,只是觉得有点恶心,不便以后维护。
但是下午突然出现一个奇怪的问题,如果参数里的中文是偶数个的话解码没有问题,但是单数的个的话就会出现乱码。比如汉字“你”就会成为“浣?”。
在网上查询答案,五花八门,大多数都没讲解原理,而且不太正确。在经过一番研究后终于找到了原因。
首先在这里简单介绍几种常见的字符集编码
ASCII编码采用单字节编码
GBK,GB18030,GB2312中文双字节编码
UTF-16双字节unicode编码
UTF-8变长多字节unicode编码,其中实践证明汉字为3个字节编码
IS08859系列,单字节编码
如果大家想详细了解各种编码的特点和产生的原因,请另外寻找资料,这里不做敷述。
下面我们来看一段代码:
运行结果如下:
浣?
-28,-67,63,
??
63,63,浣犲ソ
-28,-67,-96,-27,-91,-67,
你好
-60,-29,-70,-61,
由此可见,当我们的字符以较少字节的编码方式,被错误的读取成较大字节的编码,然后在转码成较少字节的编码方式后就会丢失数据。
比如汉字“你”,正常的十进制UTF-8,byte数组应该为[-28,-67,-96],但是进行GBK编码的时候,由于GBK是2字节方式编码,所以-28,-67构成了汉字“浣”,-96找不到对应编码方式,于是就加上了?的ASCII码63.但是汉字“你好”转成UTF-8刚好为-28,-67,-96,-27,-91,-67,是偶数个,并且2个2个的字符刚好在GBK中有对应编码,所以欺骗了编码规则,数据没有被替换,这样才正常解析回了UTF-8编码
结论:
1.任何的乱码产生都是有原因可以查询的。
2.只要以正确的方式读取原来的数据,再进行编码是不会产生丢失数据或者乱码的情况的。
3.GBK->UTF-8->GBK这个过程如果是单个汉字100%出问题,其他情况也可以类推。
解决方案:
1.整个应用统一编码格式就不会出现这个问题。
2.对参数以URLENCODING方式进行传输,但是这样在传输的时候会增加数据量。
3.在我们这个CASE中,前端直接以GBK方式传输数据,不要转为UTF-8
=============================================================
补充:
搞了半天,原来问题出在我们自己这里,看一段代码:
前台代码:
后台代码:
打印结果如下:
UTF-8
pure s ->你
浣?
-28,
-67,
-96,
===============================
i=0,j=1---你
i=0,j=2---??
i=0,j=3---??
i=0,j=4---?
i=1,j=0---你
i=1,j=2---??
i=1,j=3---??
i=1,j=4---?
i=2,j=0---?
i=2,j=1---?
i=2,j=3---?
i=2,j=4---?
i=3,j=0---浣?
i=3,j=1---浣?
i=3,j=2---???
i=3,j=4---?
i=4,j=0---??O`
i=4,j=1---??O`
i=4,j=2---??O`
i=4,j=3---??O`
可见,前面我们的分析原理的思路是正确的,但是乱码产生的原因不是js转码产生的,其实js会正确的将页面的GBK编码转换成为UTF-8,然后我们的框架会根据_input_charset=UTF-8来设置request.setCharacterEncoding("UTF-8");这样当我们从request.getParameter("param")的时候已经是正确的中文了,由于一开始我们没有加_input_charset=UTF-8这个参数,所以一直采用硬编码进行转换,结果当编码正确的时候我们又重新进行了转换,才有了GBK->UTF-8->GBK的步骤,乱码也就随之产生了。
return new String(value.getBytes("GBK"),_inut_charest);
很顺利的就调试通过了,只是觉得有点恶心,不便以后维护。
但是下午突然出现一个奇怪的问题,如果参数里的中文是偶数个的话解码没有问题,但是单数的个的话就会出现乱码。比如汉字“你”就会成为“浣?”。
在网上查询答案,五花八门,大多数都没讲解原理,而且不太正确。在经过一番研究后终于找到了原因。
首先在这里简单介绍几种常见的字符集编码
ASCII编码采用单字节编码
GBK,GB18030,GB2312中文双字节编码
UTF-16双字节unicode编码
UTF-8变长多字节unicode编码,其中实践证明汉字为3个字节编码
IS08859系列,单字节编码
如果大家想详细了解各种编码的特点和产生的原因,请另外寻找资料,这里不做敷述。
下面我们来看一段代码:
import java.io.UnsupportedEncodingException; import java.text.MessageFormat; /** * 类TestEncode.java的实现描述:测试转码类 * * @author ke.chenk 2009-3-13 下午09:01:34 * @mail lingqi1818@msn.com */ public class TestEncode { /** * 本实例在中文windows下运行,故默认字符集为GBK * * @param args */ public static void main(String[] args) { testSingle(); testDouble(); } /** * 测试单字节编码(将GBK编码以UTF-8方式读取,然后再转为GBK) */ private static void testSingle() { String s1 = encodeCovert("UTF-8", "GBK", "你"); System.out.println(s1); printByteArray(s1.getBytes()); System.out.println(); String s2 = encodeCovert("GBK", "UTF-8", s1); System.out.println(s2); printByteArray(s2.getBytes()); } /** * 测试双字节编码(将GBK编码以UTF-8方式读取,然后再转为GBK) */ private static void testDouble() { String s1 = encodeCovert("UTF-8", "GBK", "你好"); System.out.println(s1); printByteArray(s1.getBytes()); System.out.println(); String s2 = encodeCovert("GBK", "UTF-8", s1); System.out.println(s2); printByteArray(s2.getBytes()); } private static String encodeCovert(String srcCharset, String desCharset, String value) { if (value == null) { return null; } try { if ("".equals(srcCharset) || srcCharset == null) { return new String(value.getBytes(), desCharset); } if ("".equals(desCharset) || desCharset == null) { return new String(value.getBytes()); } return new String(value.getBytes(srcCharset), desCharset); } catch (UnsupportedEncodingException e) { System.out.println(MessageFormat.format( "convert encode fail srcCharset is {0} , desCharset is {1} , value is {2}", srcCharset, desCharset, value)); return value; } } private static void printByteArray(byte[] array) { for (int i = 0; i < array.length; i++) { System.out.print(array[i] + ","); } } }
运行结果如下:
浣?
-28,-67,63,
??
63,63,浣犲ソ
-28,-67,-96,-27,-91,-67,
你好
-60,-29,-70,-61,
由此可见,当我们的字符以较少字节的编码方式,被错误的读取成较大字节的编码,然后在转码成较少字节的编码方式后就会丢失数据。
比如汉字“你”,正常的十进制UTF-8,byte数组应该为[-28,-67,-96],但是进行GBK编码的时候,由于GBK是2字节方式编码,所以-28,-67构成了汉字“浣”,-96找不到对应编码方式,于是就加上了?的ASCII码63.但是汉字“你好”转成UTF-8刚好为-28,-67,-96,-27,-91,-67,是偶数个,并且2个2个的字符刚好在GBK中有对应编码,所以欺骗了编码规则,数据没有被替换,这样才正常解析回了UTF-8编码
结论:
1.任何的乱码产生都是有原因可以查询的。
2.只要以正确的方式读取原来的数据,再进行编码是不会产生丢失数据或者乱码的情况的。
3.GBK->UTF-8->GBK这个过程如果是单个汉字100%出问题,其他情况也可以类推。
解决方案:
1.整个应用统一编码格式就不会出现这个问题。
2.对参数以URLENCODING方式进行传输,但是这样在传输的时候会增加数据量。
3.在我们这个CASE中,前端直接以GBK方式传输数据,不要转为UTF-8
=============================================================
补充:
搞了半天,原来问题出在我们自己这里,看一段代码:
前台代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GBK"> <title>Insert title here</title> </head> <body> <input type="text" id="testinput"/> <input type="button" onclick="test();" value="提交"/> </body> </html> <script language="JavaScript" type="text/javascript"> function test(){ //创建浏览器兼容的XMLHttpRequest对象 var xmlhttp; try{ xmlhttp= new ActiveXObject('Msxml2.XMLHTTP'); }catch(e){ try{ xmlhttp= new ActiveXObject('Microsoft.XMLHTTP'); }catch(e){ try{ xmlhttp= new XMLHttpRequest(); }catch(e){} } } //定义XMLHttpRequest对象的事件处理程序 xmlhttp.overrideMimeType("text/html;charset=UTF-8"); xmlhttp.onreadystatechange=function(){ if(xmlhttp.readyState==4){ if(xmlhttp.status==200){ alert(xmlhttp.responseText); }else{ alert(xmlhttp.status); } } } //创建一个连接 xmlhttp.open("post","/web/servlet/TestServlet"); xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); //发送请求 xmlhttp.send("myparam="+document.getElementById("testinput").value); } </script>
后台代码:
response.setContentType("text/html"); PrintWriter out = response.getWriter(); request.setCharacterEncoding("UTF-8"); System.out.println(request.getCharacterEncoding()); String s = request.getParameter("myparam"); System.out.println("pure s ->"+s); System.out.println(new String(s.getBytes("UTF-8"),"GBK")); byte[] temp = s.getBytes("UTF-8"); for (int i = 0; i < temp.length; i++) { System.out.println(temp[i]+","); } System.out.println("==============================="); String[] charsets = { "GBK", "GB2312", "8859_1", "UTF-8", "UTF-16" }; for (int i = 0; i < charsets.length; i++) { for (int j = 0; j < charsets.length; j++) { if (i != j) { String ss = new String(s.getBytes(charsets[i]), charsets[j]); System.out.println("i="+i+",j="+j+"---"+ss); } } }
打印结果如下:
UTF-8
pure s ->你
浣?
-28,
-67,
-96,
===============================
i=0,j=1---你
i=0,j=2---??
i=0,j=3---??
i=0,j=4---?
i=1,j=0---你
i=1,j=2---??
i=1,j=3---??
i=1,j=4---?
i=2,j=0---?
i=2,j=1---?
i=2,j=3---?
i=2,j=4---?
i=3,j=0---浣?
i=3,j=1---浣?
i=3,j=2---???
i=3,j=4---?
i=4,j=0---??O`
i=4,j=1---??O`
i=4,j=2---??O`
i=4,j=3---??O`
可见,前面我们的分析原理的思路是正确的,但是乱码产生的原因不是js转码产生的,其实js会正确的将页面的GBK编码转换成为UTF-8,然后我们的框架会根据_input_charset=UTF-8来设置request.setCharacterEncoding("UTF-8");这样当我们从request.getParameter("param")的时候已经是正确的中文了,由于一开始我们没有加_input_charset=UTF-8这个参数,所以一直采用硬编码进行转换,结果当编码正确的时候我们又重新进行了转换,才有了GBK->UTF-8->GBK的步骤,乱码也就随之产生了。
发表评论
-
spring mvc介绍
2014-06-29 18:18 816项目中用到了spring mvc,整理个文档给新手入门使用,欢 ... -
【转】GCC内嵌汇编
2012-07-26 15:37 967http://wenku.baidu.com/view/58f ... -
汇编和C相互调用
2012-06-06 11:28 982这里有几个原则: 1.调用者需要在调用前声明被调用者。 c的做 ... -
commons-io引起的ygc问题
2012-05-18 16:49 1306今天接到任务,图片上传服务器的性能有问题,高峰期间YGC频率在 ... -
mongodb客户端错误集合
2011-12-20 10:38 13491错误一: 调用代码: String map = "f ... -
jmeter java请求参数配置
2011-12-20 10:36 2128<JavaSampler guiclass=&quo ... -
openfire简介
2011-09-23 15:07 26879详细文章请下载附件。。。。。。 Openfire简介 ... -
计算机缓存漫谈
2011-06-27 16:36 976见附件 见附件 见附件 -
va_list和vsnprintf
2011-06-22 15:40 1190http://blog.sina.com.cn/s/blog_ ... -
memcached源代码分析
2011-06-17 11:12 4898目录 一. 概述... 3 二 ... -
[转]关于SASL的介绍文档
2011-05-20 11:11 2http://docs. ... -
jetty服务器性能调整过程分析
2011-05-13 10:27 2622见附件 见附件 见附件 -
【转】“INT 21H”指令说明及使用方法
2011-04-07 14:29 2322很多初学汇编语言的同学可能会对INT 21H这条指令感到困 ... -
hbase-0.20.6数据写入服务端代码性能瓶颈分析
2011-03-29 16:33 1729目前我的实际配置是4台8核CPU,装4个regionServe ... -
再见c3p0
2011-03-28 16:24 1142c3p0已经很久不维护了,以后java数据库连接池的代码打算都 ... -
无侵入,系统性能监测程序,配置简单,欢迎下载
2011-03-21 09:51 2917本外挂主要目的是对系 ... -
keepalive的来龙去脉
2011-03-02 09:35 4711今天有同事反应在性能测试环境cpu load很高有500多,我 ... -
深入浅出IO程序设计—序
2011-02-24 10:31 1292作为一个程序员,除了 ... -
hbase&hadoop初探
2011-02-17 10:44 924见附件。。。 -
hbase海量数据的全量导入方法
2011-02-17 10:35 16347最近有个需求要对mysql的全量数据迁移到hbase,虽然hb ...
相关推荐
文档中主要介绍了各类字符集以及相关的字符编码,字符的显示原理,从输入到显现的整个过程,程序中出现的乱码问题以及解决方案
java字符集编码乱码详解
MySQL字符编码及乱码解决方案 · 使用多种字符集来存储字符串 · 使用多种校对规则来比较字符串 · 在同一台服务器, 同一个数据库或甚至在同一个表中使用不同字符集或校对规则来混合字符串 · 允许定义任何级别...
winform的字符串转换乱码解决
HTML特殊字符编码HTML特殊字符编码HTML特殊字符编码HTML特殊字符编码HTML特殊字符编码HTML特殊字符编码HTML特殊字符编码HTML特殊字符编码HTML特殊字符编码HTML特殊字符编码HTML特殊字符编码HTML特殊字符编码
下面小编就为大家带来一篇解决JavaEE开发中字符编码出现乱码的问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
delphi中如何解决Combobox删除字符时出现乱码
字符编码过滤器 j2ee字符字符编码 字符编码过滤器 字符编码转换 post字符转换
本文实例讲述了C#简单判断字符编码的方法。分享给大家供大家参考,具体如下: public static string GetText(byte[] buff) { string strReslut = string.Empty; if (buff.Length > 3) { if (buff[0] == 239 && ...
韩文字符编码总表
易语言字符编码转换源码,字符编码转换
Python字符编码_中文乱码.pdf
字符编码查看器是一款非常实用优秀的编程软件。这款软件支持编码之间的相互转换,可以帮助用户快速查看编码等。功能非常强大。需要的朋友可以前来本站下载。 软件介绍 字符编码查看器是一款可以帮助你轻松快速的...
java字符编码监听器
Python字符编码_中文乱码归类.pdf
判断字符编码格式代码,用C++编写的如何判断字符编码格式,UTF-8,ASCII等
最近需要用到按字节数截取字符串。在网上找了很多方法。 Encoding.Default.GetString采用的Default Encoding.UTF8.GetBytes采用的是utf-8编码。这样当然是乱码。尤其出现中文时候。 对这类数据处理当然要用统一的...
关于GBK和Unicode字符集转换乱码问题
从远程oracle数据库取数据是乱码,因为远程oracle字符集为AMERICAN_AMERICA.US7ASCII 本地oracle字符集为SIMPLIFIED CHINESE_CHINA.ZHS16GBK 所以是乱码,解决办法请下载文档 多谢 因为要下载其他资源无分 多多...
HTML特殊字符编码大全 HTML特殊字符编码大全 HTML特殊字符编码大全 HTML特殊字符编码大全