• Java字符编码的转化问题


    概述:

      我想字符串的编码问题的确会困扰到很多开发者,我最近也是被困扰到了。

      问题是这样的,我们通过二维码扫描来获得二维码中的信息。但是,我们的二维码的产生过程却是“多样化”的。即在产生二维码的时候是以不同的字符串编码类型进行编码的。比如,GBK、GB2312、UTF-8等等。而这些不同的编码类型会产生不同的字节。在Java中,GBK和GB2312都是1个汉字占2个字节,UTF-8是1个汉字占3个字节,而ISO编码则是1上汉字1个字节。这样一来,我们在扫描二维码的时候就会出现一些“阴阳怪气”的乱码字符。

      这里我们是开发二维的扫描,而二维码的生成则在来自不同的产商。


    我的前期实验:

      系统字符格式:UTF-8

      字符串"中国"的GB2312编码字节数组bs_gb和UTF-8编码字节数组bs_utf
        byte[] bs_gb = {-42, -48, -71, -6};
        byte[] bs_utf = {-28, -72, -83, -27, -101, -67};


      实验步骤:

        1.首先对bs_gb分别使用GB2312编码和UTF-8编码转化为一个中间结果:
          String gbStr1 = new String(bs_gb, "GB2312");
          String utfStr1 = new String(bs_gb, "UTF-8");
          结果:
          中国
          ?й?


        2.对utfStr1进行GB2312编码,实现从 GB2312编码 -> UTF-8编码 -> GB2312编码 的过程
          String gbStr2 = new String(utfStr1.getBytes("UTF-8"), "GB2312");
          结果:锟叫癸拷
      
        3.对bs_utf分别使用GB2312编码和UTF-8编码转化为一个中间结果:
          String gbStr3 = new String(bs_utf, "GB2312");
          String utfStr2 = new String(bs_utf, "UTF-8");
          结果:
          涓??
          中国
      
        4.对gbStr3进行UTF-8编码,实现从 UTF-8编码 -> GB2312编码 -> UTF-8编码 的过程
          String utfStr3 = new String(gbStr3.getBytes("GB2312"), "UTF-8");
          结果:
          ???
      
        5.依据上面4个步骤,进行GBK和UTF-8之间的转换实验


        实验的初步结论

          UTF-8编码和GB2312编码之间不能进行直接转化
          UTF-8编码和GBK编码之间,只能是UTF-8 -> GBK -> UTF-8


    不同编码字符之间的转化:

      UTF-8转化为Unicode

    private static final char[] hexDigit = {
    		'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
    	};
    	
        private static char toHex(int nibble) {
    		return hexDigit[(nibble & 0xF)];
    	}
    	
    	/**
         * 将字符串编码成 Unicode。
         * @param theString 待转换成Unicode编码的字符串。
    	 * @param escapeSpace 是否忽略空格
    	 * @return 返回转换后Unicode编码的字符串。
    	 */
        public static String toUnicode(String theString, boolean escapeSpace) {
            int len = theString.length();
    		int bufLen = len * 2;
    
            if (bufLen < 0) {
                bufLen = Integer.MAX_VALUE;
    		}
    
            StringBuffer outBuffer = new StringBuffer(bufLen);
            for(int x=0; x<len; x++) {
                char aChar = theString.charAt(x);
                // Handle common case first, selecting largest block that
    			// avoids the specials below
                if ((aChar > 61) && (aChar < 127)) {
    				if (aChar == '\') { 
                        outBuffer.append('\'); outBuffer.append('\');
    					continue;
    				} 
                    outBuffer.append(aChar);
    				continue;
    			}
    
                switch(aChar) {
    				case ' ': 
                        if (x == 0 || escapeSpace)
    						outBuffer.append('\');
    					outBuffer.append(' ');
    					break; 
                    case '	':
    					outBuffer.append('\');
    					outBuffer.append('t');
    					break; 
                    case '
    ':
    					outBuffer.append('\');
    					outBuffer.append('n');
    					break; 
                    case '
    ':
    					outBuffer.append('\');
    					outBuffer.append('r');
    					break; 
                    case 'f':
    					outBuffer.append('\');
    					outBuffer.append('f');
    					break; 
                    case '=': // Fall through                 case ':': // Fall through                 case '#': // Fall through                 case '!': 
                        outBuffer.append('\');
    					outBuffer.append(aChar);
    					break;
    				default: 
                        if ((aChar < 0x0020) || (aChar > 0x007e)) {
    						outBuffer.append('\');
    						outBuffer.append('u'); 
                            outBuffer.append(toHex((aChar >> 12) & 0xF));
    						outBuffer.append(toHex((aChar >>   8) & 0xF));
    						outBuffer.append(toHex((aChar >>   4) & 0xF));
                            outBuffer.append(toHex( aChar         & 0xF));
    					} else { 
                            outBuffer.append(aChar);
    					}
    				}
    		} 
            return outBuffer.toString();
    	}

      Unicode转化为UTF-8

    /**
    	 * unicode 转换成 utf-8
    	 * 
    	 * @param theString
    	 * @return
    	 */
    	public static String unicodeToUtf8(String theString) {
    		char aChar;
    		int len = theString.length();
    		StringBuffer outBuffer = new StringBuffer(len);
    		for (int x = 0; x < len;) {
    			aChar = theString.charAt(x++);
    			if (aChar == '\') {
    				aChar = theString.charAt(x++);
    				if (aChar == 'u') {
    					// Read the xxxx
    					int value = 0;
    					for (int i = 0; i < 4; i++) {
    						aChar = theString.charAt(x++);
    						switch (aChar) {
    						case '0':
    						case '1':
    						case '2':
    						case '3':
    						case '4':
    						case '5':
    						case '6':
    						case '7':
    						case '8':
    						case '9':
    							value = (value << 4) + aChar - '0';
    							break;
    						case 'a':
    						case 'b':
    						case 'c':
    						case 'd':
    						case 'e':
    						case 'f':
    							value = (value << 4) + 10 + aChar - 'a';
    							break;
    						case 'A':
    						case 'B':
    						case 'C':
    						case 'D':
    						case 'E':
    						case 'F':
    							value = (value << 4) + 10 + aChar - 'A';
    							break;
    						default:
    							throw new IllegalArgumentException(
    									"Malformed   \uxxxx   encoding.");
    						}
    					}
    					outBuffer.append((char) value);
    				} else {
    					if (aChar == 't')
    						aChar = '	';
    					else if (aChar == 'r')
    						aChar = '
    ';
    					else if (aChar == 'n')
    						aChar = '
    ';
    					else if (aChar == 'f')
    						aChar = 'f';
    					outBuffer.append(aChar);
    				}
    			} else
    				outBuffer.append(aChar);
    		}
    		return outBuffer.toString();
    	}

      而对于其GB2312的编码格式是不可以在获得一个字符串之后再转化成其他的编码格式的。比如,我的一个字符串为“中国”,我把它转成GB2312的编码格式为:涓��,再转成UTF-8就变成了�??

      不过还好,对于经过GBK和ISO-8859-1这两种格式编码之后的字符,再进行UTF-8的转化,是可以转换回来的。如下测试:

      

      结果:

      

  • 相关阅读:
    Mybatis多层嵌套查询
    UUID 唯一性实现原理
    oracle 多实例启动
    orcal启动多实例是报 ORA-00845: MEMORY_TARGET not supported onthis system
    java调用quartz 2.2.2方法总结。
    mybatis中like的使用(模糊查询)
    Orcal数据库实现主键ID自增
    spring cloud分布式关于熔断器
    spring cloud分布式健康检查
    spring cloud分布式整合zipkin的链路跟踪
  • 原文地址:https://www.cnblogs.com/fengju/p/6336061.html
Copyright © 2020-2023  润新知