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代码:
import java.io.ByteArrayOutputStream;
import java.net.MalformedURLException; import sun.misc.BASE64Decoder; public class text { public static void main(String[] args) throws MalformedURLException, Exception{ //byte[] fullByte1 = new String(str.getBytes("ISO-8859-1"), "UTF-8").getBytes("GBK");
//String fullStr = new String(fullByte1, "GBK"); /* 假设环境是以GBK编码,将数据解码成GBK编码方式,但是任然是???乱码
* 可能一:数据在编码之前已经被编码成utf-8或者ISO-8859-1
* 可能二:在打包过程中,数据被重新编码
* String temp = new String(args[0].getBytes("GBK"));
* String temp1 = new String(args[0].getBytes("gb2312"));
*/ /* 测试是否打包影响编码,结果显示并非打包影响编码
* String a = new String("短信2测试");
* String temp = new String(a.getBytes("GBK"),"utf-8");
* String temp1 = new String(temp.getBytes("utf-8"),"GBK");
* String ios = new String(a.getBytes("GBK"),"ISO-8859-1");
* String ios2 = new String(ios.getBytes("ISO-8859-1"),"GBK");
*
* System.out.print(a+'\r');
* System.out.print(temp+'\r');
* System.out.print(temp1+'\r');
* System.out.print(ios+'\r');
* System.out.print(ios2);
*/ /* 测试转为了ISO-8859-1还是UTF-8, 未能转回中文字符,应该转码成了UTF-8
* String ios2 = new String(args[0].getBytes("ISO-8859-1"),"GBK");
*/ /*测试获取到字符串的准确编码,结果为UTF-8
* String whatsencode = getEncoding(args[0]);
* System.out.println(whatsencode);
*/ /* 是否能直接由UTF-8转为GBK,并未转回中文字符,任然为问好乱码
* String ios = new String(args[0].getBytes("UTF-8"),"GBK");
* System.out.print(ios);
*/ /* 询问大学老师得知,main函数并不会对字符串编码进行变化,
* 那么会不会是脚本调用jar文件时会否进行编码转换
* 测试Windows下调用脚本是否会?乱码,脚本运行需要环境,测试不能,陷入困境
*/ /* 决定在shell脚本中将字符串转为base64编码以后传送过来,在java中解码完成后传送回脚本
* String a = new String("短信测试");
* String txt64= getBASE64(a);
* System.out.println(txt64+'\r');
*/ /*
String a = new String("短信测试");
String txt64 = getEncoding(a);
System.out.println("-----------------"+'\r');
System.out.println(txt64+'\r');
String en = enUnicode(a);
System.out.println(en);
System.out.println(deUnicode(en));
*/
System.out.println("-----------------"+'\r');
System.out.println(enUnicode("tszQxbLiytQ= 短信测试")); /*将接收到的16进制字符串数组转为字符串再转为字节数组,交换高低位*/ StringBuffer stob = new StringBuffer();
for(int i =0;i<args.length;i++){
System.out.println(args[i]);
if(args[i].length() == 4){
args[i] = swapHexHL(args[i]);
stob. append(args[i]);
}
}
String newStr = stob.toString();
System.out.println(newStr);
String Upstr = newStr.toUpperCase();
String deStr = deUnicode(Upstr);
System.out.println(deStr);
String utfStr = new String(deStr.getBytes("utf-8"));
System.out.println(utfStr); //String newStr = "ccb6c5d0e2b2d4ca000a";
//byte[] newBt = newStr.getBytes("GBK");
//System.out.println(newBt); //System.out.println(deUnicode("B6CCD0C5B2E2CAD40A00"));
/*
String txtde64 = getFromBASE64(args[0]);
System.out.println(txtde64);
*/
}
/*检测字符串编码*/
public static String getEncoding(String str) {
String encode = "GB2312";
try {
if (str.equals(new String(str.getBytes(encode), encode))) {
String s = encode;
return s;
}
} catch (Exception exception) {
}
encode = "ISO-8859-1";
try {
if (str.equals(new String(str.getBytes(encode), encode))) {
String s1 = encode;
return s1;
}
} catch (Exception exception1) {
}
encode = "UTF-8";
try {
if (str.equals(new String(str.getBytes(encode), encode))) {
String s2 = encode;
return s2;
}
} catch (Exception exception2) {
}
encode = "GBK";
try {
if (str.equals(new String(str.getBytes(encode), encode))) {
String s3 = encode;
return s3;
}
} catch (Exception exception3) {
}
return "";
}
/*对字符串进行Base64编码解码*/ public static String getBASE64(String s) {
if (s == null) return null;
return (new sun.misc.BASE64Encoder()).encode( s.getBytes() );
}
public static String getFromBASE64(String s) {
if (s == null) return null;
BASE64Decoder decoder = new BASE64Decoder();
try {
byte[] b = decoder.decodeBuffer(s);
return new String(b);
} catch (Exception e) {
return null;
}
} /*将中文与16进制转换*/
private static String hexString = "0123456789ABCDEF";
public static String enUnicode(String str) {
// 根据默认编码获取字节数组
byte[] bytes = str.getBytes();
StringBuilder sb = new StringBuilder(bytes.length * 2);
// 将字节数组中每个字节拆解成2位16进制整数
for (int i = 0; i < bytes.length; i++) {
sb.append(hexString.charAt((bytes[i] & 0xf0) >> 4));
sb.append(hexString.charAt((bytes[i] & 0x0f) >> 0));
}
return sb.toString();
}
public static String deUnicode(String bytes) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(
bytes.length() / 2);
// 将每2位16进制整数组装成一个字节
for (int i = 0; i < bytes.length(); i += 2)
baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString
.indexOf(bytes.charAt(i + 1))));
return new String(baos.toByteArray());
} /*对获得的16进制数据进行处理,高低位转换*/ public static String swapHexHL(String temp){
if (temp == null) return null;
String high = (String) temp.subSequence(0,2);
String low = (String) temp.subSequence(2,4);
String newString = low +high;
return newString;
}
/*去掉XML不认可的字符0x0-0x20*/
public static String delcode(String in) {
StringBuffer out = new StringBuffer(); // Used to hold the output.
char current; // Used to reference the current character.
if (in == null || ("".equals(in)))
return ""; // vacancy test.
for (int i = 0; i < in.length(); i++) {
current = in.charAt(i);
if ((current == 0x9) || (current == 0xA) || (current == 0xD)
|| ((current > 0x20) && (current <= 0xD7FF))
|| ((current >= 0xE000) && (current <= 0xFFFD))
|| ((current >= 0x10000) && (current <= 0x10FFFF))
|| (current < 0x0))
out.append(current);
}
return out.toString().trim();
}
}
放上从网上找来的乱码分析:
一个汉字对应两个问号 在通过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中转回的方式实现结果
放上最后的脚本代码:
#!/bin/bash
str1="\"$1 $2\"" //$1,$2,$3,是运行脚本时传送的参数
str2="$3"
str3=`echo ${str2} | od -h`
str4=`echo ${str3:}`
/flash/system/appr/SafeRun.bin "/jre/bin/java -jar /appr/adiap.jar ${str1} ${str4}" >&
一个汉字对应两个问号
在通过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涓 枃
GBK编码和UTF-8编码互转的大坑的更多相关文章
- 从Java String实例来理解ANSI、Unicode、BMP、UTF等编码概念
转(http://www.codeceo.com/article/java-string-ansi-unicode-bmp-utf.html#0-tsina-1-10971-397232819ff9a ...
- 编码知识梳理(UTF-8, Unicode, GBK, X509, ANSI, VIM中编码)
编码小结 1 初识编码 所谓编码,是信息从一种形式或格式转换为另一种形式的过程. 字符编码,从自然语言的字符的一个集合(如字母表或音节表),到其他东西的一个集合(如号码或电脉冲)的映射 ANSI:wi ...
- GB2312、GBK和UTF-8三种编码以及QT中文显示乱码问题
1.GB2312.GBK和UTF-8三种编码的简要说明 GB2312.GBK和UTF-8都是一种字符编码,除此之外,还有好多字符编码.只是对于我们中国人的应用来说,用这三种编码 比较多.简单的说一下, ...
- 告别乱码,针对GBK、UTF-8两种编码的智能URL解码器的java实现(转)
效果图 字符 字符是早于计算机而存在,从人类有文明那时起,人们就用一个个符号代表世间万象.如ABC,如“一.二.三”. 字符集 字符集是所有字符的集合. XXX字符集 给字符集中的每一个字符套上一个序 ...
- url 编码(percentcode 百分号编码)(转载)
原文地址:http://www.cnblogs.com/leaven/archive/2012/07/12/2588746.html http://www.imkevinyang.com/2009 ...
- 【编码】_C#中编码名称(Name)与页面标识(CodePage)的关系_编码gb2312的获取
在写C#代码时,发现VS提供没有直接提供gb2312的中文编码, 所以,需要找到对应编码名称的codepage来调用想要的编码方式. 下面是微软编程提供的所有编码信息,包括编码名称,编码代码页标识符, ...
- 签名、BOM头、编码、Windows记事本编码、java编码解码的那些事
对于Windows记事本: ANSI :GB2312 java中应使用GBK解码 Unicode :有签名的UTF-16LE java中应使用UTF-16解码 Unicode big endian : ...
- url 编码(percentcode 百分号编码)
http://www.imkevinyang.com/2009/08/%E8%AF%A6%E8%A7%A3javascript%E4%B8%AD%E7%9A%84url%E7%BC%96%E8%A7% ...
- CodePage------Encoding 类支持的编码以及与这些编码关联的代码页(CodePage)
Encoding 类 .NET Framework 4 表示字符编码. 继承层次结构 System.Object System.Text.Encoding System.Text.ASCII ...
随机推荐
- 【windows开发实现记事本程序——逻辑篇1】
1. 主要内容 从本节开始介绍windows开发实现记事本程序的逻辑实现部分.本节的主要内容有以下3点: 1. 主窗口定义 -- 主要介绍记事本主界面窗口对应的窗口类及实现方案 2. RichEdi ...
- 【转】lua random()
先来看看这两段代码: ① math.randomseed(os.time())for i=1,10 do n = math.random(10) print(n) 运行结果是: 63210754341 ...
- Skew Join与Left Semi Join相关
Skew Join 真实数据中数据倾斜是一定的, hadoop 中默认是使用 hive.exec.reducers.bytes.per.reducer = 1000000000 也就是每个节点的red ...
- c语言中3n+1溢出问题解决
3n+1问题是一个简单有趣而又没有解决的数学问题.这个问题是由L. Collatz在1937年提出的.克拉兹问题(Collatz problem)也被叫做hailstone问题.3n+1问题.Hass ...
- Thinkphp---练习:数据的增删改查
利用ThinkPHP连接数据库的增删改查的例题:用到的数据库表名Info表,Nation表 数据显示页面:MainController.class.php中的方法(增删改查全包括--function ...
- set_time_limit() 控制页面运行时间
当你的页面有大量数据时,建议使用set_time_limit()来控制运行时间,默认是30s,所以需要你将执行时间加长点,如 set_time_limit(300) ,其中将秒数设为0 ,表示持续运 ...
- python中read、readline和readlines的区别
read 读取整个文件 readline 读取下一行 readlines 读取整个文件到一个迭代器以供我们遍历(读取到一个list中,以供使用,比较方便). 123.txt内容 ...
- java中dynamic web project与web project 的区别 [转]
原帖地址:http://blog.sina.com.cn/s/blog_46726d2401013jlk.html 文章框架: 1.Dynamic Web Project 概念 2.eclipse ...
- VS2013程序打包部署(图解),vs2013部署
VS2013程序打包部署(图解),vs2013部署 首先要说明的是VS解决方案配置下的Debug模式和Release模式有什么区别.Debug模式通常称为调试模式,它包含调试信息,未对代码进行优化,方 ...
- mysql rr和rc区别
<pre name="code" class="html">1. 数据库事务ACID特性 数据库事务的4个特性: 原子性(Atomic): 事务中的 ...