编码问题分析
个人经验:
这几天在公司,发报文调试接口的时候由于使用UTF8跟GBK两种编码很头疼。页面显示为utf8码,但是解析报文使用的却是GBK,这样就会出现两种情况,要么你调试页面是正常的,报文是乱的,要么调试页面使用乱码格式,报文显示正常!。。。。总结后:发现一个项目中必须要统一使用一种编码格式!然后就是不同编码必定会有差异,GBK编码跟utf8编码是不可能存在转换关系的,用什么样的编码格式发送的就需要使用该格式去解析!
GBK/GB2312透析:
import java.io.UnsupportedEncodingException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GBKEncodeUtil {
/**
* GB2312/GBK编码类
*
* 机内码,区位码,国标码 三者间存在联系,由于机内码,国标码一般以四位十六进制的形式存在,区位码以四位十进制表示。
*
* 举例子:
* 德 ---区位码:2134
* 机内码: 高位字节 = 21(十进制) + A0H(十六进制) = 15H + A0H = B5H
* 低位字节 = 34(十进制) + A0H(十六进制) = 22H + A0H = C2H
* 机内码: B5C2H
* 国标码: 高位字节 = 21(十进制) + 20H(十六进制) = 15H + 20H = 35H
* 低位字节 = 34(十进制) + 20H(十六进制) = 22H + 20H = 42H
* 国标码: 3542H
*
* 同理: 国标码 = 机内码 - 8080H
*/
public static void main(String[] args) {
String str = "德".trim();
System.out.println(str);
System.out.println("机内码:0x" + getJineiMa(str));
System.out.println("区位码:" + getLocationCode(str));
System.out.println("国标码:0x" + getGBCode(str));
System.out.println(getCharacter("B0A1"));
}
/**
* 判断str是否为汉字
* @param str 待检测值
* @return true 是 false 不是
*/
public static boolean isCharacter(String str){
Pattern p_str = Pattern.compile("[\\u4e00-\\u9fa5]+");
Matcher m = p_str.matcher(str);
if(m.find()&&m.group(0).equals(str)){
return true;
}
return false;
}
/**
* 获取机内码
* @param chineseName
* @return 汉字的机内码 String类型
*/
public static String getJineiMa(String chineseName){
StringBuffer sb = new StringBuffer();
try {
char[]ch = chineseName.toCharArray();
for (char c : ch){
if (isCharacter(String.valueOf(c))){
byte[]by = String.valueOf(c).getBytes("GBK");
for (byte b : by){
sb.append(Integer.toHexString(b & 0xff));
}
}else{
byte b = (byte) c;
sb.append(Integer.toHexString(b & 0xff));
}
}
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString().toUpperCase().trim();
}
/**
* 获得汉字区位码
*
* @param chineseName 汉字
*
* @return 单个汉字区位码
*/
public static String getLocationCode(String chineseName){
// 先判断chinese是否为汉字
if (!isCharacter(chineseName)) return "输入的不是汉字!";
String jiNeiMa = getJineiMa(chineseName);
String highOrder = jiNeiMa.substring(0, 2); // 高位
String lowOrder = jiNeiMa.substring(2, 4); // 低位
String quWeiMa = String.valueOf((Integer.parseInt(highOrder, 16) - 0xA0)) + String.valueOf(Integer.parseInt(lowOrder, 16) - 0xA0);
return quWeiMa;
}
/**
* 获取 国标码
* @param chineseName
* @return
*/
public static String getGBCode(String chineseName){
// 先判断chinese是否为汉字
if (!isCharacter(chineseName)) return "输入的不是汉字!";
int jiNeiMa = Integer.parseInt(getJineiMa(chineseName), 16);
String gbMa = Integer.toHexString(jiNeiMa - 0x8080);
return gbMa;
}
/**
根据机内码获取汉字
* @param quWeiMa
* @return 汉字
*/
public static String getCharacter(String jiNeiMa){
byte b1 = (byte) Integer.parseInt(jiNeiMa.substring(0, 2), 16);
byte b2 = (byte) Integer.parseInt(jiNeiMa.substring(2, 4), 16);
String str = null;
try {
str = new String(new byte[]{b1,b2}, "GBK");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return str;
}
}
运行结果:
德
机内码:0xB5C2
区位码:2134
国标码:0x3542
啊