这几天遇到一个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> 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/bash2 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涓 枃