关于字符编码与解码的小结

针对下面几种常用的字符码表

ASCII :     美国标准信息交换码,使用7位二进制数来表示所有的大小写字母,数字0~9,标点符号以及在美式英语中使用的特殊控制字符
ISO8859-1 : 拉丁码表,兼容ASCII,还包括西欧语言,希腊语,泰语,阿拉伯语等
GB2312 :    中文码表,兼容ASCII,每个英文占1个字节,中文占2个字节(2个字节都为负数,最高位都为1)
GBK,GB18030:兼容GB2312,包含跟多中文,每个英文占一个字节,中文占2个字节(第1个字节为负数,第2个字节可正可负)
Unicode :   国际标准码,它为每种语言的每个字节设定了统一且唯一的二进制编码,以满足跨语言,跨平台进行文本转换,处理的要求,每个字节占2个字符.Java中存储的字符类型就是使用Unicode编码
UTF-8 :     是针对Unicode的可变长编码,可以用来表示Unicode标准中的任何字符,其中,英文占1个字节,中文占3个字节,这是程序开发中最常用的字符码


一级编解码:     中文可以与所有支持中文的码表如GB2312, GBk, GB18030,  UTF-8, Unicode转换

例如:

String str = "博客";
byte[] b1 = str.getBytes("GBK");    //GB2312为中文码表,GBK兼容GB2312
String str2 = new String(b1,"GBK");
System.out.println(str2);

//结果是: "博客", 编解码成功

二级编解码:    要想实现二级转换, 必须先将中文成功进行一级编码 

例1:

String str = "管理";	
byte[] b1 = str.getBytes("Unicode");    //中文可以与Unicode相互转换
String str1 = new String(b1,"ISO8859-1");
byte[] b2 = str1.getBytes("ISO8859-1"); 
String str2 = new String(b2,"Unicode");
System.out.println(str2);

//结果是 "管理", 编解码成功
String str = "管理";	
byte[] b1 = str.getBytes("ISO8859-1");    //中文不能与ISO8859-1相互转换
String str1 = new String(b1,"Unicode");    
byte[] b2 = str1.getBytes("Unicode");
String str2 = new String(b2,"ISO8859-1");
System.out.println(str1);

//结果是 "?", 编解码失败

例2: GBK与UTF-8不能互转

String str = "传智";
System.out.println("Unicode: " + str);

byte[] b1 = str.getBytes("UTF-8");
printx("b1字节流UTF-8 " , b1);    //静态方法,printx(String str, byte[] bs),用于逐个打印字节

String str1 = new String(b1,"GBK");
System.out.println("GBK: " + str1);

byte[] b2 = str1.getBytes("GBK");
printx("b2字节流GBK ", b2);

String str2 = new String(b2,"UTF-8");
System.out.println("UTF-8: " + str2);
Unicode: 传智
b1字节流UTF-8 : [-28] [-68] [-96] [-26] [-103] [-70] 
GBK: 浼犳櫤
b2字节流GBK : [-28] [-68] [-96] [-26] [-103] [-70] 
UTF-8: 传智

可以看到,UTF-8字节码与GBK字节码相同

UTF-8 将1个中文字符对应于3个字节, 所以"传智"一共6个字节

GBK 将1个中文字符对应于2个字节,解析出错误的字符串,共3个字符

这3个错误字符被原样返回为6个字节码,再由UTF-8恢复成2个中文字符

成功


若将原字符串由"传智"改为"传智播", 3个字符:

Unicode: 传智播
b1字节流UTF-8 : [-28] [-68] [-96] [-26] [-103] [-70] [-26] [-110] [-83] 
GBK: 浼犳櫤鎾?
b2字节流GBK : [-28] [-68] [-96] [-26] [-103] [-70] [-26] [-110] [63] 
UTF-8: 传智??

分析:

Unicode"传智播"对应于UTF-8共9个字节: [-28 -68 -96], [-26 -103 -70], [-26 -110 -83]

GBK将这9个字节解码, 2个一组, 共5组:  [-28 -68], [-96 -26], [-103 -70], [-26 -110], [-83]

可见, 前4组成功解码(虽然不是正确的中文字符), 但第5组只有一个字节, 无法正常解码, 为"?", 接下来,由GBK对 "浼犳櫤鎾?" 进行编码: [-28 -68], [-96 -26], [-103 -70], [-26 -110], [63]

前8个字节码与之前的相同, 第9个产生了变化: [-83]->[63], 最后, 由UTF-8解码时,由于第9个字节产生变化, 前6个字节解码成功, 后3个字节解码失败: [-28 -68 -96], [-26 -103 -70], [-26 -110 63]


试探1:

Unicode->ASCII->ISO8859-1->ISO8859-1->ASCII            失败    //中文字符不能与ASCII直接转换
Unicode->GBK->ISO8859-1->ISO8859-1->GBK            成功
Unicode->Unicode->ISO8859-1->ISO8859-1->Unicode    成功
Unicode->UTF-8->ISO8859-1->ISO8859-1->UTF-8        成功

//ISO8859-1可以作为中间字符集, 但中文字符必须能与边缘字符集兼容转换, 如: GB2312, GBk, GB18030, UTF-8, Unicode


试探2:

Unicode->ASCII->Unicode->Unicode->ASCII                失败
Unicode->GBK->Unicode->Unicode->GBK                    失败
Unicode->ISO8859-1->Unicode->Unicode->ISO8859-1        失败
Unicode->ASCII->Unicode->Unicode->ASCII                失败

//国际标准码Unicode不能作为中间字符集

结论:

  1. GBK可以作为中间字符集为UTF-8转换,但中文字符必须为偶数
  2. ISO8859-1可以作为中间字符集为可以与中文字符兼容的字符集转换

猜你喜欢

转载自blog.csdn.net/qq_36420790/article/details/79889455