什么是编码?
简单来说就是把一段文字信息转化为数字信息。比如我想的一句话
“我要成为很帅的企业家”—-如何转化为数字信息呢? 做一个码表。如图
然后这个表有坐标,每个字就有他独特的坐标,把坐标信息发给你想告诉的那个人,那个人再对着表就能得到你想传递给他的信息了。这就是编码的基本原理。
这个编码是美国人想出来的(因为互联网都是他们发明出来的),他们就为自己的英文单词做了码表就是 ASCII码。他们把需要用到的字符,字母收集完了以后只要128个,可以算一下128 –2的7次方,但是计算机存储的最小单位是一个字节就是2的8次方位。所以他们就是前面加1个0,就构成了8位。后来随着计算机的发展,很多其他国家也需要用到码表,所以原来的ASCll码表就不够用了,就有了新的码表。
新的码表是怎么建的呢? 就是在原来的ASCll码表上拓展来的,把ASCll码表变大新加入的放其他位置,原来他的位置不变。所以英文就从来没有乱码问题。
然后不同的地区的国家就有不同的码表,像我国就有gb2313和他的升级版本gbk,欧洲就有iso8859-1 还有java的 Unicode
ASCII:美国标准信息交换码。用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表用一个字节的8位表示。
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
Unicode:国际标准码,融合了多种文字。
UTF-8:一种变长的unicode码的实现方式,由1~4个字节表示。(Unicode的优化版本吧。变长的)
那么中文乱码是怎么回事?怎么来的呢?
我们一般在网络上浏览网页什么的都是通过Tomcat服务器发布的,而这个服务器是欧洲人做的,当我们使用Tomcat发布的时候,过程是这样的。
那么怎么解决呢? 很简单,你是因为经过了IOS8859-1这个编码才错误的,我就把你的str 再经过IOS8859-1解码一次,我再用自己的utf-8编码不就好了吗?
来看代码
public class StringEncodingDemo {
public static void main(String[] args) {
/**
* 两个方法:
* 1.str.getBytes(指定编目)--- 按照某一码表编码
* 2.new String(Bytes[],指定编码);--- 按照某一码表解码 成字符串
*/
try {
String str = "abc达哥真帅啊";
byte bs [] = str.getBytes("utf-8"); //这个采用MyEclipse默认编码,--我的是UTF-8
// byte bs [] = str.getBytes("ISO885-1");//这个是采用指定的编目
for(byte b:bs){
System.out.print(b+" ");
}
System.out.println();
String info = new String(bs, "ISO8859-1");
System.out.println(info);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
解决之后的代码
package cn.hncu.io.iop;
import java.io.UnsupportedEncodingException;
public class StringEncodingDemo {
public static void main(String[] args) {
/**
* 两个方法:
* 1.str.getBytes(指定编目)--- 按照某一码表编码
* 2.new String(Bytes[],指定编码);--- 按照某一码表解码 成字符串
*/
try {
System.out.println("---要发送的信息---");
String str = "abc达哥真帅啊";
System.out.println(str);
System.out.println("----解决之前-----");
byte bs [] = str.getBytes("utf-8"); //这个采用MyEclipse默认编码,--我的是UTF-8
// byte bs [] = str.getBytes("ISO885-1");//这个是采用指定的编目
for(byte b:bs){
System.out.print(b+" ");
}
System.out.println();
String info = new String(bs, "ISO8859-1");
System.out.println(info);
System.out.println("----解决之后----");
byte bs2[] = info.getBytes("ISO8859-1");
for(byte b:bs2){
System.out.print(b+" ");
}
String str2 = new String(bs2,"utf-8");
System.out.println();
System.out.println(str2);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
结果
然后下面的代码是我的大神老师讲的时候用大代码。嘻嘻
/*以后我们开发后台会遇到一个乱码场景:
* 1、浏览器编码并发送(str的字节数组–码值)—>
* 2、Tomcat接收并解码(查iso8859-1表,得到字符串name),
* 传参给 MyServlet —>
* 3、MyServlet接收到的name参数就是乱码
*/
package cn.hncu.io.io3;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.junit.Test;
public class StringEncodingDemo {
@Test//字符串编码
public void demo1() throws IOException{
String str="?hello你好!";
//byte[] bs = str.getBytes();//用默认码表
//用指定码表---会抛异常,因为码表中可能不存在该字符,比如ISO8859-1码表中就不存在中文(如果非要用它编码则编出来的是63即'?')
//byte[] bs = str.getBytes("utf-8");//用指定码表
byte[] bs = str.getBytes("gbk"); //用指定码表
for(byte b:bs){
System.out.print(b+" ");
}
System.out.println();
}
// @Test//字符串解码 ---如果用的码表和编码时不一样,乱码!
public void demo2() throws IOException{
byte bs[] = {63,104,101,108,108,111,-60,-29,-70,-61,33};
//String info = new String(bs);//用默认码表
String info = new String(bs,"gb2312");//gb2312和gbk是兼容的,只是gbk中补了一些原来gb2312没有收集的中文字符
System.out.println(info);
}
/*以后我们开发后台会遇到一个乱码场景:
* 1、浏览器编码并发送(str的字节数组--码值)--->
* 2、Tomcat接收并解码(查iso8859-1表,得到字符串name),
* 传参给 MyServlet --->
* 3、MyServlet接收到的name参数就是乱码
*/
// @Test//利用字符编码的原理 解决中文乱码 ----解码解错可以补救!
public void demo3() throws IOException{
//模拟浏览器的处理(编码)
String str="张三";
byte bs[] = str.getBytes("utf-8");
//模拟Tomcat的处理(解码--解错了)
String str2 = new String(bs,"iso8859-1");
System.out.println(str2);//乱码
//解决中文乱码
byte bs2[] = str2.getBytes("iso8859-1");//用ISO8859-1重新编码,还原出原来正确的码值
//用正确的码值查正确的码表
String ss= new String(bs2,"utf-8");
System.out.println("ss:"+ss);
}
//编码编错必挂!
//@Test
public void demo4() throws IOException{
String str = "你好!";
byte bs[] = str.getBytes("iso8859-1");//编码编错了
String ss = new String(bs,"iso8859-1");
System.out.println(ss);
}
}