字符编码问题之手动转码并不万能
来源:互联网 发布:中国税务网络大学app 编辑:程序博客网 时间:2024/06/06 14:16
- 引言
相信大家在最开始接触web的时候,因为Tomcat服务器默认的URIEncoding是ISO8859-1。应该产生过中文乱码问题,某些前辈就会告诉你,可以手动转码。new String(str.getBytes("IOS8859-1"),"gbk");
这句话大家应该不陌生,如果页面编码方式是gbk,Tomcat URIEncoding是ISO8859-1。这样编码再解码,看着确实合理,而且能解决问题。但是其实手动转码局限性是比较大的。
- 基本概念介绍
首先你应该知道编码是干什么,编码就是把字符按照规定的字符集转换成 0 1 的字节流形式.解码,是把相应的0 1字节流按照规定字符集转换成相应字符的形式。然后你应该知道,Java中的字符都是按照Unicode字符集进行编码的。也就是说,JVM管理的内存中的,字符都是以Unicode编码形式存在的。而非JVM的内存中,字符是以各种各样的字符集进行编码的,当Java程序与外界交互的时候(如I/O),就会涉及到编码解码问题。在Java中,不同的字符集都是以Unicode作为桥梁相互转换的。
- String两个常用API原理介绍。
public static void main(String[] args) throws Exception {String str = "天";byte[] b = str.getBytes("gbk");show(b);} public static void show(byte[] b){ for (int i = 0; i < b.length; i++){ System.out.print( b[i] + " "); } System.out.println(); }
结果:-52 -20
byte[] b = str.getBytes("gbk");
这句话的意思是把str中的字符 天 用gbk字符集进行编码,返回编码后的字节数组。
把-51 -20的2进制的表示形式就是 天 在gbk字符集中的编码。
看着简单,实际上是进行了以下的操作。
相当于从内存中取出天字的Unicode编码,然后利用Unicode到gbk的转换算法,得到天字的gbk编码
如图1
String str2 = new String(b,"gbk");
这句话的意思是把字节数组b,用gbk字符集解码生成新的字符串。
实际上是把字节数组b通过gbk到unicode的转换算法转换成unicode码
如图2
- 手动转码
public class Test4 {public static void main(String[] args) throws Exception {String str = "天";byte[] b = str.getBytes("gbk");show(b);String str2 = new String(b,"utf-8");//类似I/O时,用了与发送方不匹配字符集。导致下面需要手动转码byte[] b2 = str2.getBytes("utf-8");//企图转回来show(b2);System.out.println(new String(str2.getBytes("utf-8"),"gbk"));} public static void show(byte[] b){ for (int i = 0; i < b.length; i++){ System.out.print(b[i]+ " "); } System.out.println(); }}
结果如下:
-52 -20
-17 -65 -67 -17 -65 -67
锟斤拷
-17 -65 -67 -17 -65 -67
锟斤拷
上面的过程与我们开头提到的web中手动转码的问题非常相像。
但是,这次为什么失败了呢。先让我们看看上面代码做了什么。
相当于
1.首先把str通过gbk编码得到了字节数组b
2.把字节数组b用uft8字符集解码生成新的字符str2
3.把str2字符用utf-8字符集编码成字节数组b2
(2)(3)看似可逆。
实际上是
1.首先把str通过gbk编码得到了字节数组b
2.利用字节数组b,通过utf-8到unicode的转换算法生成新的字符str2
3.把字符串str2利用utf-8到unicode的转换算法解码生成字节数组b2
为什么b的值与b2的值不同呢?
现是字节数组通过utf-8解码生成字符,然后字符通过utf-8编码生成字节数组。
明明是可逆的操作,为什么不能还原.让b2与b相等呢?
确实这种转换算法实际上是可逆的。
但问题出现在哪了呢?
其实大家忽略了一个细节我们的b字节数组里面的值是gbk编码形式的。
把一个gbk形式的字节流 通过utf-8到unicode转换算法 转成 unicode码。这个过程之中因为utf-8与gbk的不兼容。导致了转换过程出现了错误。
所以在,你想转回来的时候,你用错误的结果无法转换回来。
再来看看最开头提到的例子:
public class Test4 {public static void main(String[] args) throws Exception {String str = "天";byte[] b = str.getBytes("gbk");show(b);String str2 = new String(b,"ISO8859-1");byte[] b2 = str2.getBytes("ISO8859-1");show(b2);System.out.println(new String(str2.getBytes("ISO8859-1"),"gbk"));} public static void show(byte[] b){ for (int i = 0; i < b.length; i++){ System.out.print(b[i]+ " "); } System.out.println(); }}
结果如下:
-52 -20
-52 -20
天
-52 -20
天
为什么用ISO8859-1就成功了呢?为什么用ISO8859-1就可逆了呢?
如果详细说会比较麻烦,你可以认为在这种操作的时候ISO8859-1和gbk的兼容性比较好。
如果你觉得只说兼容性这个词太抽象的话,可以稍微这么理解。
b[]字节数组里面存的是gbk编码,如果用utf-8到unicode的转换算法。这个字节数组里面的某些位用这种算法无法解析,于是数据就出现了错误,数据错误之后,你想转换回来当然不行了(所谓的兼容性不好)。
b[]字节数组里面存的是gbk编码,如果用iso8859-1到unicode的转换算法。虽然字节数组的某些位不是标准的iso8859-1的格式,但是这种算法仍然能按照某种方式解析,所以数据没出现错误,所以你想转换回来的时候,还能转换回来(所谓的兼容性好)。
所以说,手工转码不是万能的。
最佳实践:事先调整好发送方与接收方的字符集,最好别手工转码。
以上纯属个人观点,欢迎讨论。
- 字符编码问题之手动转码并不万能
- 字符编码问题之手动转码并不万能
- RoR之字符编码问题
- tomcat部署之字符编码问题
- 字符流编码问题之写操作
- 编码问题之转码
- 钱并不是万能的
- Python字符编码的一个相对万能的处理方法
- Python基础知识之字符编码和转码
- python 学习之路(字符编码与转码)
- JAVA中文字符编码问题(转)
- Java 字符编码问题
- Java 字符编码问题
- 字符编码问题
- 关于字符编码问题
- 字符编码问题摘要
- MySQL字符编码问题
- 关于字符编码问题
- HTML学习笔记02(HTML 标签)
- android开机自启动的后台Service的实现
- linux下获取键盘按键
- Servlet运行周期与原理流程
- CocoaPacketAnalyzer的使用方法
- 字符编码问题之手动转码并不万能
- 如何安装,卸载eclipse中的ADT,或者更新ADT
- 使用金山快盘做git的服务器
- 原创利用flashpaper实现百度文库、豆丁网文档预览功能
- error LNK2001: unresolved external symbol "public: virtual struct QMetaObject const
- 什么是左式堆
- Android OpenGL ES 简明开发教程
- 程序员都应该知道的福利
- 在你的博客中增加google+按钮