Android乱码以及编码转化
To live is to function,that is all there is in living.
乱码是安卓开发中常常遇到的事情,AndroidStudio默认的是UTF-8编码,而网站常用GBK(GB2312老版)编码,为了避免网络请求出现问题,常常会对网络接口中的的文字进行编码,也会对返回的数据进行编码,如何在UTF-8的环境下将汉字成功的转换成其他编码尼,这是该篇博客为读者解答的事情,读完此篇博客,你将对编码有新的认识,从此乱码与你是路人,编码不在是难事,此篇博客乃一家之言,若有问题请直言以待校正。
首先,介绍一下编码,解码的概念,以及为什么要编码 。
编码:将源对象内容按照一种标准转换为一种标准格式内容。
解码:和编码对应的,它使用和编码相同的标准将编码内容还原为最初的对象内容。
编解码的目的最初是为了加密信息,经过加密的内容不知道编码标准的人很难识别,已经有数千年历史了。
而现在编解码种类非常多,主要目的则是为了信息交换。
除了加密,目前程序中常见的如字符编解码,HTML编解码,URL编解码,邮件编解码,多媒体编解码等。编码是为了符合传输的要求,解码是为了还原成我们能识别的信息。
例如字符编解码,字符编码在一系列数字与人们将文本输入到计算机中时希望看到的字符之间提供映射。因为世界上有不同的语言和文字,所以需要将不同的文字编码以通过计算机处理和传输。
再比如多媒体编解码,因为有多种不同格式的图像声音,所以它们各自有自己编解码标准。
那么今天我们主要处理安卓中的文字编码解码问题,至于加密在后续文章我将会提到。
介绍一个工具——站长工具之编码转换http://tool.chinaz.com/tools/utf-8.aspx 可以将经行多种编码之间的转换,当然站长工具还有其他功能,君可慢慢细看
我需要的编码:
已知晓的文字:动漫卡通
后台需要的编码为:%25u52A8%25u6F2B%25u5361%25u901A
接下来使用站长工具进行编码处理,如下图:
一:直接使用UrlEncode
可以看见其对应的编码是:%e5%8a%a8%e6%bc%ab%e5%8d%a1%e9%80%9a,这和我们的需求相差很远,那么如果再一次进行编码会不会达到我们的期望尼,接下来拭目以待:
二次UrlEncode对应的编码是:%25e5%258a%25a8%25e6%25bc%25ab%25e5%258d%25a1%25e9%2580%259a,所以简单的
URLEncode.encode()方法并不能达到需求,那么怎么办尼
接下来仍然使用站长工具,复制“动漫卡通”,测试其他编码是否能实现。。。终于在使用GBK——UTF-8的时候我看见了希望。
待编码文字:动漫卡通 需得到的编码:%25u52A8%25u6F2B%25u5361%25u901A
目前通过GBK转UTF-8可以达到:动漫卡通
同志们有没有觉得革命已经胜利了尼!数字部分已经出来了,如果String.replace(“&#x”,“25u%”)来替换便可以实现目的,但是国内网站的中文环境是多数是GBK(GBK2312),而studio的环境默认的是utf-8,如何在UTF-8的环境下实现这一转变尼?
接下来我们需要了解一个新的知识:Uniconde编码。
什么是Unicode编码尼?请看下图(来源于百度百科)
知道了这一点接下来我们就可以开始干了,捋一捋思路,我们首先将utf-8环境下的“动漫卡通”转化为Unicode编码下A,然后再讲A转换为GBK编码下的B(得到纯正的GBK编码),然后在将B转换为Unicode编码下的C;
接下来我们试一试是不是这样尼,我们打印出一条日志:
03-12 17:12:55.869 23869-23869/com.itwangxia.hackhome I/----GAME->>>>: encodeUTF: 动漫卡通 utf2gbk = \U52A8\U6F2B\U5361\UFFFF901A utf2unicode = \U52A8\U6F2B\U5361\UFFFF901A
可以发现,我们在将UTF编码转为Unicode编码下的B的时候已经得到了需要的编码(排除\U以及FFFF的干扰)
至于为什么是这样,我将在下一篇博客中介绍编码的问题。
实现了诸如%25u52A8%25u6F2B%25u5361%25u901A此类的编码。
接下来粘贴代码,主要是其他编码转换为Unicode编码,至于编码之间互相转换还是借助Unicode编码来实现的。
/** *将GBK编码转换为UTF-8编码 * */ public String gbk2utf8(String gbk) { String l_temp = GBK2Unicode(gbk); l_temp = unicodeToUtf8(l_temp); return l_temp; }/** *将UTF-8编码转换为GBK编码 * */ public static String utf82gbk(String utf) { String l_temp = utf8ToUnicode(utf); l_temp = Unicode2GBK(l_temp); return l_temp; }public static String GBK2Unicode(String str) { StringBuffer result = new StringBuffer(); for (int i = 0; i < str.length(); i++) { char chr1 = (char) str.charAt(i); if (!isNeedConvert(chr1)) { result.append(chr1); continue; } result.append("\\u" + Integer.toHexString((int) chr1)); } return result.toString(); }/** *将gbk编码转换为unicode编码 *主要编码方法 *//** *将Unicode编码转换为GBK编码 *主要解码方法 */ public static String Unicode2GBK(String dataStr) { int index = 0; StringBuffer buffer = new StringBuffer(); int li_len = dataStr.length(); while (index < li_len) { if (index >= li_len - 1 || !"\\u".equals(dataStr.substring(index, index + 2))) { buffer.append(dataStr.charAt(index)); index++; continue; } String charStr = ""; charStr = dataStr.substring(index + 2, index + 6); char letter = (char) Integer.parseInt(charStr, 16); buffer.append(letter); index += 6; } return buffer.toString(); } public static boolean isNeedConvert(char para) { return ((para & (0x00FF)) != para); }/** *将UTF-8编码转换为Unicode编码 *主要编码方法 */ public static String utf8ToUnicode(String inStr) { char[] myBuffer = inStr.toCharArray(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < inStr.length(); i++) { // char ch=myBuffer[i]; // if((int)ch < 10){ // sb.append("\\u000"+(int)ch); // continue; // } UnicodeBlock ub = UnicodeBlock.of(myBuffer[i]); if (ub == UnicodeBlock.BASIC_LATIN) { sb.append(myBuffer[i]); } else if (ub == UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) { int j = (int) myBuffer[i] - 65248; sb.append((char) j); } else { short s = (short) myBuffer[i]; String hexS = Integer.toHexString(s); String unicode = "\\u" + hexS; sb.append(unicode.toUpperCase()); } } return sb.toString(); }/** *将UTF-8编码转换为GBK编码 *主要解码方法 */ 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(); }
接下来介绍一些其他方法以帮助浏览此博文的朋友:
try { String s = new String("卡通动漫".getBytes(), "GBK"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); }该方法是不可取的,得到的是乱码,不建议使用
而如果像是这种乱码进入游戏→点左上角头像→兑换码
使用
Html.fromHtml(String.format(formate,gDesc))
就足以搞定了,主要是后台防止文字乱码问题。
javaScript中的常用escape()编码 和unescape()解码
escape编码,例如中文:网侠小鲜肉 escape编码为:%u7f51%u4fa0%u5c0f%u9c9c%u8089
- public static String escape(String src) {
- int i;
- char j;
- StringBuffer tmp = new StringBuffer();
- tmp.ensureCapacity(src.length() * 6);
- for (i = 0; i < src.length(); i++) {
- j = src.charAt(i);
- if (Character.isDigit(j) || Character.isLowerCase(j)
- || Character.isUpperCase(j))
- tmp.append(j);
- else if (j < 256) {
- tmp.append("%");
- if (j < 16)
- tmp.append("0");
- tmp.append(Integer.toString(j, 16));
- } else {
- tmp.append("%u");
- tmp.append(Integer.toString(j, 16));
- }
- }
- return tmp.toString();
- }
unescape解码
- public static String unescape(String src) {
- StringBuffer tmp = new StringBuffer();
- tmp.ensureCapacity(src.length());
- int lastPos = 0, pos = 0;
- char ch;
- while (lastPos < src.length()) {
- pos = src.indexOf("%", lastPos);
- if (pos == lastPos) {
- if (src.charAt(pos + 1) == 'u') {
- ch = (char) Integer.parseInt(src
- .substring(pos + 2, pos + 6), 16);
- tmp.append(ch);
- lastPos = pos + 6;
- } else {
- ch = (char) Integer.parseInt(src
- .substring(pos + 1, pos + 3), 16);
- tmp.append(ch);
- lastPos = pos + 3;
- }
- } else {
- if (pos == -1) {
- tmp.append(src.substring(lastPos));
- lastPos = src.length();
- } else {
- tmp.append(src.substring(lastPos, pos));
- lastPos = pos;
- }
- }
- }
- return tmp.toString();
- }
- 但是切记在安卓开发过程中,我们需要注意使用的网络请求框架的编码方式,如果不注意很有可能报错如下:
-
这时我们只需要在在escape编码里面将“%u”换成“%25u”即可
(以上是我个人开发中面对的一些问题及困惑,若有误导,望君海涵,也望君扶正,谢谢)