概念
计算机只认识0101
这样的二进制字节,而人天生只对a,b.c,中,大
这些字符敏感,而且写代码的目的是为了让计算机能读懂,主题是计算机,所以自然就衍生出了两个概念,如图1;
编码(encode):
从字符到字节;解码(decode):
从字节到字符;
那解码和编码也不能瞎解,瞎编吧,必须要有规范的对照的转化字典表吧,因为世界各地语言存在差异,编码和解码的工作也就不一样,就出了不同的字符集编码解码大字典,如 ASCII,ISO8859-1,GBK,GB18030,Unicode,UTF-8;
ASCII,ISO8859-1,GBK,GB18030,Unicode,UTF-8详解
程序中经常遇到乱码的问题,产生的乱码的原因就是因为计算机直接存储字符,需要将字符转化为二进制的,不同的转化规则就对应了不同的编码方式,而保持不乱的条件就是编码方式和解码方式保持一致,今天就一起阅尽天下编码,心中自然无码。
首先先来看一眼编码的发展历程图,如图2:
ASCII:首先大家都知道计算机由美国人发明,那ASCII码正是最早用来将127字符的编码到计算机里面的一套编码;
ISO8859-1:ASCII的扩充,可以编码一些较为生僻的拉丁字符;
GB2312:当计算机来到中国,ISO8859-1显然就不够用了,存储不了我们伟大的汉字,最找也有提出将汉字转化为拼音存入计算机的想法,但经过国人的不屑努力,开发出了GB2312的国内最早,用得最多的简体中文编码;
BIG5:与此同时港澳台同胞开发了BIG5来编码繁体汉字;
GBK:GB2312的扩充,把BIG5码的思想融入进来,既可以表示简体中文也可以表示繁体中文;
GB18030:GBK的扩充,可以表示少数民族的字符,现在的国标码;
Shift_JIS/Euc_kr:深受我大中华文化熏陶的周边国家日本,韩国方块象形字,在计算机引进后一样遇到了这样的问题,就自己开发了各自的国标码;
Unicode:每个国家都来一套国标码,那大家还怎么记?最重要跨国合作项目还做不做?因为大家的项目编码不同的话一样遇到乱码的,于是天下大事分久必合,Unicode诞生了;
UTF-8:Unicode已经满足要求了啊,为啥还有UTF-8,那是因为Unicode使用2个字节,但对于老美的字母存储来说,一个字节完全够用,用Unicode强行加大存储负担,本来ASCII码,1T的内容,强行被Unicode整出了2T,但是现在中,日,韩等象形字国家这么多,老美又避免不了和他们网络交流,于是UTF-8可变长的编码就诞生了,UTF-8,一个字节表示字母,3个字节普通汉字,4~6个字节表示生僻字;
UTF-16:定长,两个字节的unicode,分为大端(高段位地址)和小端(低段位地址),FF PE表示小端,FE FF表示大端;
下表是常用的编码和表示汉字或字母时的字节数:
编码 | 字母 | 汉字 |
---|---|---|
ISO8859-1/ASCII | 1个字节 | 无法表示 |
GBK/GB18030/Unicode | 2个字节 | 通常的2个字节(生僻字4个字节) |
UTF-8 | 1个字节 | 通常的3个字节(生僻字4~6个字节) |
乱码的原因
综上所述,乱码的原因一般就两个;
- 编码解码字符集不一致;
常人遇到的一般是这种,只需要另存为一下换成对应的字符集即可解决;
- 编码解码字符集一致了,但是该字符集所要覆盖的字节长度没有得到满足,发生了截断;
程序员处理程序有bug所致,需要给到适应的字节长度;
Java代码为例说明乱码
package cm.rowyet.Test17IO;
import java.io.UnsupportedEncodingException;
public class FileDemo06 {
public static void main(String[] args) throws UnsupportedEncodingException {
String msg="a,努力努力再努力!";
System.out.println("---------------------编码后字节数----------------------------");
//编码,字节数组
byte[] datas=msg.getBytes(); //使用默认工程的字符集 默认为UTF-8
System.out.println(datas.length);
System.out.println("---------------------解码后字符----------------------------");
System.out.println();
//正确解码
//String(byte[] bytes,int offset, int length,String charsetName);
//byte[] bytes 字节数组;
//offset 开始解析的位置
//length 字节长度
//charsetName 字符集
msg=new String(datas,0,datas.length,"utf8");
System.out.println(msg);
System.out.println("---------------------字节数不够导致的解码乱码----------------------------");
//乱码 字节数不够
msg=new String(datas,0,datas.length-1,"utf8");
System.out.println(msg);
msg=new String(datas,0,datas.length-2,"utf8");
System.out.println(msg);
System.out.println("---------------------字符集不统一导致的解码乱码----------------------------");
//字符集不统一
msg=new String(datas,0,datas.length,"gbk");
System.out.println(msg);
}
}
输出结果为:
---------------------编码后字节数----------------------------
24
---------------------解码后字符----------------------------
a,努力努力再努力!
---------------------字节数不够导致的解码乱码----------------------------
a,努力努力再努力
a,努力努力再努�
---------------------字符集不统一导致的解码乱码----------------------------
a,鍔姏鍔姏鍐嶅姫鍔�!
Process finished with exit code 0