锁定老帖子 主题:理解并解决GBK转UTF-8奇数中文乱码
该帖已经被评为新手帖
|
|
---|---|
作者 | 正文 |
发表时间:2011-06-18
最后修改:2011-06-20
最近在做一个反馈功能,把数据反馈到对方公司网站,我公司是GBK编码,对方公司是UTF-8编码。因此,我需要将GBK编码数据转换成UTF-8编码数据,这样对方网站才不会乱码。最简单的方法是将HttpClient的ContentCharset设置为utf-8;如果ContentCharset是gbk并且又不想设置为utf-8,那么就需要将数据转换成UTF-8编码再发到对方网站。
问题出现:GBK转UTF-8时,奇数个中文会乱码,偶数个中文不会乱码。 public static void encodeError() throws UnsupportedEncodingException { String gbk = "我来了"; String utf8 = new String(gbk.getBytes("UTF-8")); //模拟UTF-8编码的网站显示 System.out.println(new String(utf8.getBytes(),"UTF-8")); } /* 我来?? */ 前面三个中文,后面一个中文,都是奇数 public static void encodeError2() throws UnsupportedEncodingException { String gbk = "今年是2011年"; String utf8 = new String(gbk.getBytes("UTF-8")); //模拟UTF-8编码的网站显示 System.out.println(new String(utf8.getBytes(),"UTF-8")); } /* 今年??011?? */
原因:为什么只有奇数个中文才乱码,偶数个却不乱码?下面来分析原因 public static void analyze() throws UnsupportedEncodingException { String gbk = "我来了"; String utf8 = new String(gbk.getBytes("UTF-8")); for (byte b : gbk.getBytes("UTF-8")) { System.out.print(b + " "); } System.out.println(); for (byte b : utf8.getBytes()) { System.out.print(b + " "); } } /* -26 -120 -111 -26 -99 -91 -28 -70 -122 -26 -120 -111 -26 -99 -91 -28 -70 63 */ 注意最后一个字节不同,上面一行才是正确的UTF-8编码。那么为什么下面一行最后一个字节是63,而不是-122呢?这就是导致乱码的原因所在。
这里讲一下怎么通过计算增加字节,不深究的读者可以跳过此段。为了醒目,直接用代码讲解 public static void gbk2Utf() throws UnsupportedEncodingException { String gbk = "我来了"; char[] c = gbk.toCharArray(); byte[] fullByte = new byte[3*c.length]; for (int i=0; i<c.length; i++) { String binary = Integer.toBinaryString(c[i]); StringBuffer sb = new StringBuffer(); int len = 16 - binary.length(); //前面补零 for(int j=0; j<len; j++){ sb.append("0"); } sb.append(binary); //增加位,达到到24位3个字节 sb.insert(0, "1110"); sb.insert(8, "10"); sb.insert(16, "10"); fullByte[i*3] = Integer.valueOf(sb.substring(0, 8), 2).byteValue();//二进制字符串创建整型 fullByte[i*3+1] = Integer.valueOf(sb.substring(8, 16), 2).byteValue(); fullByte[i*3+2] = Integer.valueOf(sb.substring(16, 24), 2).byteValue(); } //模拟UTF-8编码的网站显示 System.out.println(new String(fullByte,"UTF-8")); }
现在我们来找出最后一个字节是63,而不是-122的原因。 public static void analyze2() throws UnsupportedEncodingException { String gbk = "我来了"; byte[] utfBytes = gbk.getBytes("UTF-8");//得到9个字节 String utf8 = new String(utfBytes);//问题就出在这 System.out.print(utf8); } /* 鎴戞潵浜? */ 因为文件是GBK编码,new String(utfBytes)默认就是new String(utfBytes,"GBK")。它会2个字节2个字节地转换成字符,当字节是奇数时最后1个字节转字符就会计算错误,然后直接赋予最后这个字符为?,对应ASCII代码就是63。
解决问题 public static void correctEncode() throws UnsupportedEncodingException { String gbk = "我来了"; String iso = new String(gbk.getBytes("UTF-8"),"ISO-8859-1"); for (byte b : iso.getBytes("ISO-8859-1")) { System.out.print(b + " "); } System.out.println(); //模拟UTF-8编码的网站显示 System.out.println(new String(iso.getBytes("ISO-8859-1"),"UTF-8")); } /* -26 -120 -111 -26 -99 -91 -28 -70 -122 我来了 */
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-06-19
和刚看到的另两篇也是说编码的文章结合理解,有了一些收获,有个疑问,ISO-8859-1既然是单字节,那如果UTF-8转成字节数组占了3个字节,那是会转成3个字符吗?
|
|
返回顶楼 | |
发表时间:2011-06-19
arsenal04 写道 和刚看到的另两篇也是说编码的文章结合理解,有了一些收获,有个疑问,ISO-8859-1既然是单字节,那如果UTF-8转成字节数组占了3个字节,那是会转成3个字符吗? 是的,ISO-8859-1是一个字节表示一个字符,UTF-8是三个字节表示一个字符。 |
|
返回顶楼 | |
发表时间:2011-06-20
学习了, 好多时候乱码让俺这个小白头痛不已。。。
|
|
返回顶楼 | |
发表时间:2011-06-20
讲的非常好,解决了以前的疑惑。。。
|
|
返回顶楼 | |
发表时间:2011-06-20
学习了,楼主加油!
|
|
返回顶楼 | |
发表时间:2011-06-20
chenfeng0104 写道 arsenal04 写道 和刚看到的另两篇也是说编码的文章结合理解,有了一些收获,有个疑问,ISO-8859-1既然是单字节,那如果UTF-8转成字节数组占了3个字节,那是会转成3个字符吗?
是的,ISO-8859-1是一个字节表示一个字符,UTF-8是三个字节表示一个字符。 这种说法不对,UTF-8有一个字节的字符也有2个字节的字符也有3个字节的字符 |
|
返回顶楼 | |
发表时间:2011-06-20
问题是当我把你写的方法 输出的没有乱码
java文件编码格式utf-8 |
|
返回顶楼 | |
发表时间:2011-06-20
非常感谢,终于明白如何解决乱码了
|
|
返回顶楼 | |
发表时间:2011-06-20
String gbk = "我来了";
String iso = new String(gbk.getBytes("UTF-8"),"UTF-8"); System.out.println(iso); 直接这样不行吗? |
|
返回顶楼 | |