• 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+'
    ');
     29          * System.out.print(temp+'
    ');
     30          * System.out.print(temp1+'
    ');
     31          * System.out.print(ios+'
    ');
     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+'
    ');
     59          */
     60         
     61         
     62         /*
     63         String a = new String("短信测试");
     64         String txt64 = getEncoding(a);
     65         System.out.println("-----------------"+'
    ');
     66         System.out.println(txt64+'
    ');
     67         String en = enUnicode(a);
     68         System.out.println(en);
     69         System.out.println(deUnicode(en));
     70         */
     71         System.out.println("-----------------"+'
    ');
     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锟斤拷锟斤拷
    
    
    编码过程中错误诊断参考
    )一个汉字对应一个问号
    在通过ISO-8859-1从字符串获取字节数组时,
    由于一个Unicode转换成一个byte,
    当遇到不认识的Unicode时,转换为0x3F,
    这样无论用哪种编码构造时都会产生一个?乱码。
    
    
    )一个汉字对应两个问号
    在通过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涓 枃

  • 相关阅读:
    [RxJS] sample
    [Whole Web] SQL INJECTION
    [RxJS] Using iif
    [React] Animate SVG Paths with Framer Motion
    bash 教程5 shell 流程控制 条件判断 重定向 read [MD]
    bash 教程4 shell 脚本 调试 环境 [MD]
    『前端算法』数组合并两个有序数组
    块设备读写测试
    IO栈整体认知
    MySQL [Warning] Can’t create test file xxx lowertest(转)
  • 原文地址:https://www.cnblogs.com/blitheG/p/5606475.html
Copyright © 2020-2023  润新知