概述:
我想字符串的編碼問題的確會困擾到非常多開發人員。我近期也是被困擾到了。
問題是這種,我們通過二維碼掃描來獲得二維碼中的信息。可是。我們的二維碼的產生過程卻是“多樣化”的。即在產生二維碼的時候是以不同的字符串編碼類型進行編碼的。比方,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 '\t': outBuffer.append('\\'); outBuffer.append('t'); break; case '\n': outBuffer.append('\\'); outBuffer.append('n'); break; case '\r': 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 = '\t'; else if (aChar == 'r') aChar = '\r'; else if (aChar == 'n') aChar = '\n'; 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的轉化,是能夠轉換回來的。例如以下測試:
結果: