GBK编码和UTF-8编码互转的大坑

  这几天遇到一个BUG,问题很简单,解决却花了3、4天,特意记录下来。

  linux环境下,将默认编码设置为GBK以后,运行GBK编码的脚本,调用一个Java的jar包,然后总jar包中返回GBK字符串。但是不知道是哪里出了问题,返回的参数一直是问号乱码。

  放上脚本代码:

#!/bin/bash
#str="\"$1       $2      $3\""
str="\"http://iap.zh.gmcc.net/WebService/Notify.asmx    chenliang3      短信测试\""
/flash/system/appr/SafeRun.bin 0 0 "/jre/bin/java -jar /appr/adiap.jar ${str}" 2>&1

  放上调试时的Java代码:

  1 import java.io.ByteArrayOutputStream;
  2 import java.net.MalformedURLException;
  3
  4 import sun.misc.BASE64Decoder;
  5
  6
  7 public class text {
  8
  9     public static void main(String[] args) throws MalformedURLException, Exception{
 10
 11         //byte[] fullByte1 = new String(str.getBytes("ISO-8859-1"), "UTF-8").getBytes("GBK");
 12         //String fullStr = new String(fullByte1, "GBK");
 13
 14         /* 假设环境是以GBK编码,将数据解码成GBK编码方式,但是任然是???乱码
 15          * 可能一:数据在编码之前已经被编码成utf-8或者ISO-8859-1
 16          * 可能二:在打包过程中,数据被重新编码
 17          * String temp = new String(args[0].getBytes("GBK"));
 18          * String temp1 = new String(args[0].getBytes("gb2312"));
 19          */
 20
 21         /* 测试是否打包影响编码,结果显示并非打包影响编码
 22          * String a = new String("短信2测试");
 23          * String temp = new String(a.getBytes("GBK"),"utf-8");
 24          * String temp1 = new String(temp.getBytes("utf-8"),"GBK");
 25          * String ios = new String(a.getBytes("GBK"),"ISO-8859-1");
 26          * String ios2 = new String(ios.getBytes("ISO-8859-1"),"GBK");
 27          *
 28          * System.out.print(a+‘\r‘);
 29          * System.out.print(temp+‘\r‘);
 30          * System.out.print(temp1+‘\r‘);
 31          * System.out.print(ios+‘\r‘);
 32          * System.out.print(ios2);
 33          */
 34
 35         /* 测试转为了ISO-8859-1还是UTF-8, 未能转回中文字符,应该转码成了UTF-8
 36          * String ios2 = new String(args[0].getBytes("ISO-8859-1"),"GBK");
 37          */
 38
 39         /*测试获取到字符串的准确编码,结果为UTF-8
 40          * String whatsencode = getEncoding(args[0]);
 41          * System.out.println(whatsencode);
 42          */
 43
 44
 45         /* 是否能直接由UTF-8转为GBK,并未转回中文字符,任然为问好乱码
 46          * String ios = new String(args[0].getBytes("UTF-8"),"GBK");
 47          * System.out.print(ios);
 48          */
 49
 50         /* 询问大学老师得知,main函数并不会对字符串编码进行变化,
 51          * 那么会不会是脚本调用jar文件时会否进行编码转换
 52          * 测试Windows下调用脚本是否会?乱码,脚本运行需要环境,测试不能,陷入困境
 53          */
 54
 55         /* 决定在shell脚本中将字符串转为base64编码以后传送过来,在java中解码完成后传送回脚本
 56          * String a = new String("短信测试");
 57          * String txt64= getBASE64(a);
 58          * System.out.println(txt64+‘\r‘);
 59          */
 60
 61
 62         /*
 63         String a = new String("短信测试");
 64         String txt64 = getEncoding(a);
 65         System.out.println("-----------------"+‘\r‘);
 66         System.out.println(txt64+‘\r‘);
 67         String en = enUnicode(a);
 68         System.out.println(en);
 69         System.out.println(deUnicode(en));
 70         */
 71         System.out.println("-----------------"+‘\r‘);
 72         System.out.println(enUnicode("tszQxbLiytQ= 短信测试"));
 73
 74         /*将接收到的16进制字符串数组转为字符串再转为字节数组,交换高低位*/
 75
 76         StringBuffer stob = new StringBuffer();
 77         for(int i =0;i<args.length;i++){
 78             System.out.println(args[i]);
 79             if(args[i].length() == 4){
 80                 args[i] = swapHexHL(args[i]);
 81                 stob. append(args[i]);
 82             }
 83         }
 84         String newStr = stob.toString();
 85         System.out.println(newStr);
 86         String Upstr = newStr.toUpperCase();
 87         String deStr = deUnicode(Upstr);
 88         System.out.println(deStr);
 89         String utfStr = new String(deStr.getBytes("utf-8"));
 90         System.out.println(utfStr);
 91
 92
 93         //String newStr = "ccb6c5d0e2b2d4ca000a";
 94         //byte[] newBt = newStr.getBytes("GBK");
 95         //System.out.println(newBt);
 96
 97         //System.out.println(deUnicode("B6CCD0C5B2E2CAD40A00"));
 98         /*
 99         String txtde64 = getFromBASE64(args[0]);
100         System.out.println(txtde64);
101         */
102     }
103     /*检测字符串编码*/
104     public static String getEncoding(String str) {
105            String encode = "GB2312";
106           try {
107               if (str.equals(new String(str.getBytes(encode), encode))) {
108                    String s = encode;
109                   return s;
110                }
111            } catch (Exception exception) {
112            }
113            encode = "ISO-8859-1";
114           try {
115               if (str.equals(new String(str.getBytes(encode), encode))) {
116                    String s1 = encode;
117                   return s1;
118                }
119            } catch (Exception exception1) {
120            }
121            encode = "UTF-8";
122           try {
123               if (str.equals(new String(str.getBytes(encode), encode))) {
124                    String s2 = encode;
125                   return s2;
126                }
127            } catch (Exception exception2) {
128            }
129            encode = "GBK";
130           try {
131               if (str.equals(new String(str.getBytes(encode), encode))) {
132                    String s3 = encode;
133                   return s3;
134                }
135            } catch (Exception exception3) {
136            }
137           return "";
138        }
139     /*对字符串进行Base64编码解码*/
140
141     public static String getBASE64(String s) {
142         if (s == null) return null;
143         return (new sun.misc.BASE64Encoder()).encode( s.getBytes() );
144     }
145     public static String getFromBASE64(String s) {
146         if (s == null) return null;
147         BASE64Decoder decoder = new BASE64Decoder();
148         try {
149             byte[] b = decoder.decodeBuffer(s);
150             return new String(b);
151         } catch (Exception e) {
152             return null;
153         }
154     }
155
156     /*将中文与16进制转换*/
157     private static String hexString = "0123456789ABCDEF";
158     public static String enUnicode(String str) {
159         // 根据默认编码获取字节数组
160         byte[] bytes = str.getBytes();
161         StringBuilder sb = new StringBuilder(bytes.length * 2);
162         // 将字节数组中每个字节拆解成2位16进制整数
163         for (int i = 0; i < bytes.length; i++) {
164             sb.append(hexString.charAt((bytes[i] & 0xf0) >> 4));
165             sb.append(hexString.charAt((bytes[i] & 0x0f) >> 0));
166         }
167         return sb.toString();
168     }
169     public static String deUnicode(String bytes) {
170         ByteArrayOutputStream baos = new ByteArrayOutputStream(
171                 bytes.length() / 2);
172         // 将每2位16进制整数组装成一个字节
173         for (int i = 0; i < bytes.length(); i += 2)
174             baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString
175                     .indexOf(bytes.charAt(i + 1))));
176         return new String(baos.toByteArray());
177     }
178
179     /*对获得的16进制数据进行处理,高低位转换*/
180
181     public static String swapHexHL(String temp){
182         if (temp == null) return null;
183         String high = (String) temp.subSequence(0,2);
184         String low = (String) temp.subSequence(2,4);
185         String newString = low +high;
186         return newString;
187     }
188     /*去掉XML不认可的字符0x0-0x20*/
189     public static String delcode(String in) {
190         StringBuffer out = new StringBuffer(); // Used to hold the output.
191         char current; // Used to reference the current character.
192         if (in == null || ("".equals(in)))
193             return ""; // vacancy test.
194         for (int i = 0; i < in.length(); i++) {
195             current = in.charAt(i);
196             if ((current == 0x9) || (current == 0xA) || (current == 0xD)
197                     || ((current > 0x20) && (current <= 0xD7FF))
198                     || ((current >= 0xE000) && (current <= 0xFFFD))
199                     || ((current >= 0x10000) && (current <= 0x10FFFF))
200                     || (current < 0x0))
201                 out.append(current);
202         }
203         return out.toString().trim();
204     }
205 }

  放上从网上找来的乱码分析:

一个汉字对应两个问号

在通过GBK从字符串获取字节数组时,由于一个Unicode转换成两个byte,如果此时用ISO-8859-1或用UTF-8构造字符串就会出现两个问号。

若是通过ISO-8859-1构造可以再通过上面所说的错上加错恢复(即再通过从ISO-8859-1解析,用GBK构造);
若是通过UTF-8构造则会产生Unicode字符"\uFFFD",不能恢复,若再通过String-UTF-8〉ByteArray-GBK〉String,则会出现杂码,如a锟斤拷锟斤拷

编码过程中错误诊断参考
1)一个汉字对应一个问号
在通过ISO-8859-1从字符串获取字节数组时,
由于一个Unicode转换成一个byte,
当遇到不认识的Unicode时,转换为0x3F,
这样无论用哪种编码构造时都会产生一个?乱码。

2)一个汉字对应两个问号
在通过GBK从字符串获取字节数组时,由于一个Unicode转换成两个byte,如果此时用ISO-8859-1或用UTF-8构造字符串就会出现两个问号。
若是通过ISO-8859-1构造可以再通过上面所说的错上加错恢复(即再通过从ISO-8859-1解析,用GBK构造);
若是通过UTF-8构造则会产生Unicode字符"\uFFFD",不能恢复,若再通过String-UTF-8〉ByteArray-GBK〉String,则会出现杂码,如a锟斤拷锟斤拷

3)一个汉字对应三个问号在通过UTF-8从字符串获取字节数组时,由于一个Unicode转换成三个byte,如果此时用ISO-8859-1构造字符串就会出现三个问号;用GBK构造字符串就会出现杂码,如a涓 枃

  最后还是没有解决乱码的问题,而是通过将字符串转16进制,在Java中转回的方式实现结果

  放上最后的脚本代码:

 

1 #!/bin/bash
2 str1="\"$1    $2\""    //$1,$2,$3,是运行脚本时传送的参数
3 str2="$3"
4 str3=`echo ${str2} | od -h`
5 str4=`echo ${str3:8}`
6 /flash/system/appr/SafeRun.bin 0 0 "/jre/bin/java -jar /appr/adiap.jar ${str1} ${str4}" 2>&1

一个汉字对应两个问号

在通过GBK从字符串获取字节数组时,由于一个Unicode转换成两个byte,如果此时用ISO-8859-1或用UTF-8构造字符串就会出现两个问号。

若是通过ISO-8859-1构造可以再通过上面所说的错上加错恢复(即再通过从ISO-8859-1解析,用GBK构造);若是通过UTF-8构造则会产生Unicode字符"\uFFFD",不能恢复,若再通过String-UTF-8〉ByteArray-GBK〉String,则会出现杂码,如a锟斤拷锟斤拷

编码过程中错误诊断参考1)一个汉字对应一个问号在通过ISO-8859-1从字符串获取字节数组时,由于一个Unicode转换成一个byte,当遇到不认识的Unicode时,转换为0x3F,这样无论用哪种编码构造时都会产生一个?乱码。

2)一个汉字对应两个问号
在通过GBK从字符串获取字节数组时,由于一个Unicode转换成两个byte,如果此时用ISO-8859-1或用UTF-8构造字符串就会出现两个问号。
若是通过ISO-8859-1构造可以再通过上面所说的错上加错恢复(即再通过从ISO-8859-1解析,用GBK构造);若是通过UTF-8构造则会产生Unicode字符"\uFFFD",不能恢复,若再通过String-UTF-8〉ByteArray-GBK〉String,则会出现杂码,如a锟斤拷锟斤拷

3)一个汉字对应三个问号在通过UTF-8从字符串获取字节数组时,由于一个Unicode转换成三个byte,如果此时用ISO-8859-1构造字符串就会出现三个问号;用GBK构造字符串就会出现杂码,如a涓 枃

时间: 2024-11-05 13:33:40

GBK编码和UTF-8编码互转的大坑的相关文章

告别乱码,针对GBK、UTF-8两种编码的智能URL解码器的java实现(转)

效果图 字符 字符是早于计算机而存在,从人类有文明那时起,人们就用一个个符号代表世间万象.如ABC,如“一.二.三”. 字符集 字符集是所有字符的集合. XXX字符集 给字符集中的每一个字符套上一个序号后的字符集.常见的XXX字符集有ASCLL字符集.Unicode字符集等等,不同种字符集为每个字符编的序号不同,包含的字符数量也不同. GBK.UTF-8 GBK.UTF-8是一种编码编码格式.当然,你也可以说unicode是一种编码格式,因为它的的确确为每个字符编了一个码,没错,可是unicod

UTF-8、GBK、GBK2312等字符编码的区别和vim乱码等相关问题研究。

转自本人博客:xge技术博客 http://www.xgezhang.com/char_encodind_vim.html 关于字符编码的问题在做项目的时候经常都会出现,但一直没有很系统的研究过,今天早上系统的看了几篇文章.在此整理分享以下. 三种编码方式的简介: gb2312(又称为GB 2312-80)编码是一个简体中文字符集的中国国家标准,全称为<信息交换用汉字编码字符集·基本集>,又称为GB0,由中国国家标准总局发布,1981年5月1日实施.GB2312编码适用于汉字处理.汉字通信等系

多线程批量转换文件编码, 从GBK, GB2312编码转换到UTF-8编码(Python)

# coding=utf-8 # author:Jeffrey Ma # version:0.1 # build 2 # created on:2015年3月31日 # description: 1. 批量转换文件编码,从GBK GB2312编码转换到UTF-8编码 # 2. 支持指定目录下所有的文件的转换,包括子目录中的文件 # 3. 支持检测原始编码,对已经是UTF-8编码的文件,不做转换 # 4. 支持只转换指定扩展名的编码 # 5. 支持多线程转换和控制台输出 # 6. 支持控制台显示线

(转载)GBK、UTF8、UNICODE编码转换

GBK.UTF8.UNICODE编码转换 1 string GBKToUTF8(const std::string& strGBK) 2 { 3 int nLen = MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, NULL, 0); 4 WCHAR * wszUTF8 = new WCHAR[nLen]; 5 MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, wszUTF8, nLen);

GBK编码字节流与UTF-8编码字节流的转换

import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class BianMaDemo4 { public static void main(String[] args) throws IOException, FileNotFoundException { /* * * GB

关于编码问题以及不同平台编码及string与编码的关系

说明:这里简要说明一下不同平台的编码不同,c语言中的char *与编码的关系这些问题,及对通常困扰的乱码问题做个总结 一.编码 简单说,就是计算机识别信息的一种格式,ascal.utf-8这些都属于编码,计算机根据这些编码标准,解读出内容.l 二.ANSI.ascll.utf8.unicode等说明 1.  ASCII和Ansi编码 字符内码(charcter code)指的是用来代表字符的内码.读者在输入和存储文档时都要使用内码,内码分为 单字节内码 -- Single-Byte charac

刨根究底字符编码之九——字符编码方案的演变与字节序

字符编码方案的演变与字节序 一.字符编码方案的演变 1. 前文已经提及,编号字符集CCS(简称字符集)与字符编码方式CEF(简称编码方式)这两个概念,在早期并没有必要严格区分. 在Unicode编码方案出现之前,字符集及其具体的编码方式是绑定耦合在一起的,因此,"字符集"."编码"或"编码方式"甚至"编码方案"这几个概念经常相互指代.彼此混用. 比如,字符集里的字符编号(即码点编号)在很多文章里也称之为字符编码.字符码.码点.

字符编码介绍及不同编码区别

UNICODE,GBK,UTF-8区别 简单来说,unicode,gbk和大五码就是编码的值,而utf-8,uft-16之类就是这个值的表现形式.而前面那三种编码是一兼容的,同一个汉字,那三个码值是完全不一样的.如"汉"的uncode值与gbk就是不一样的,假设uncode为a040,gbk为b030,而uft-8码,就是把那个值表现的形式.utf-8码完全只针对uncode来组织的,如果GBK要转UTF-8必须先转uncode码,再转utf-8就OK了. 详细的就见下面转的这篇文章. 谈谈Un

字符串编码解析及字符编码输出

package 字符串编码解析; import java.io.UnsupportedEncodingException; public class Demo1 { public static void main(String[] args) throws UnsupportedEncodingException { String str = "中国"; //使用默认编码 byte[] gbk = str.getBytes("GBK"); //使用utf-8来编码