您好,登錄后才能下訂單哦!
今天小編給大家分享一下web前端中文亂碼是怎么產生的的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
中文亂碼的產生原因:解碼方式和編碼方式不一致。一個中文字符以utf-8編碼會轉成3個byte,如果以gbk編碼會轉成2個byte;而一個英文字符以utf-8編碼會轉成1個byte,如果以gbk編碼會轉成1個byte。
不知道有沒有人這樣認為過,一個字符串不僅僅包含字符,還有隱藏著它的編碼信息。比如java中String str = "你好";我之前是這樣認為的,str這個字符串隱藏著它的編碼方式unicode編碼或者gbk、iso-8859-1等。這種理解是錯誤的,字符就是字符沒有任何其他信息,正確的理解應該是,人在一個文件中所看到的字符串是系統經過把內存中的數碼信息讀取也再解碼成一些字符最后顯示,就是當你雙擊打開一個文本文件時系統會把內存的數碼信息讀取顯示出來,當你保存一個文本文件時系統會把這個文件以你所設置的編碼方式編碼,再放進內存中。
所以說亂碼也是一些字符,只是奇怪的字符而已,并沒有什么”碼“。
我們經常看到網上這樣解釋亂碼原因:亂碼是因為解碼方式和編碼方式不一致導致的,這句話本身沒有錯,但同樣這句話的本身就是把亂碼概括了而已,它并不能幫助你理解亂碼。
所以我們要提的問題是:為什么解碼方式和編碼方式不一致會出現亂碼。
這里以utf-8,gbk,iso-8859-1三種編碼方式為例。
@Test
public void testEncode() throws Exception {
String str = "你好",en = "h?h";
System.out.println("========中文字符utf-8=======");
byte[] utf8 = str.getBytes(); // 以utf-8方式編碼 ,default:utf-8
for (byte b : utf8) {
System.out.print(b + "\t");
}
System.out.println("\n"+"========英文字符utf-8=======");
byte[] utf8_en = en.getBytes(); // 以utf-8方式編碼 ,default:utf-8
for (byte b : utf8_en) {
System.out.print(b + "\t");
}
System.out.println("\n"+"========中文字符gbk=========");
byte[] gbk = str.getBytes("gbk");
for (byte b : gbk) {
System.out.print(b + "\t");
}
System.out.println("\n"+"========英文字符gbk=========");
byte[] gbk_en = en.getBytes("gbk");
for (byte b : gbk_en) {
System.out.print(b + "\t");
}
String s = new String(utf8,"utf-8");
String s1 = new String(utf8,"gbk");
System.out.println("\n"+s + "====gbk:" + s1);
}
測試上面方法,打印的結果是:
========中文字符utf-8=======
-28 -67 -96 -27 -91 -67
========英文字符utf-8=======
104 63 104
========中文字符gbk=========
-60 -29 -70 -61
========英文字符gbk=========
104 63 104
你好====gbk:浣犲ソ
------------------------------------------------------------------------------------
一個中文字符以utf-8編碼會轉成3個byte,如果以gbk編碼會轉成2個byte;
一個英文字符以utf-8編碼會轉成1個byte,如果以gbk編碼會轉成1個byte。
從打印的最后一行結合29-31行代碼可以看出,如果把byte數組utf8 以utf-8的方式解碼不會有亂碼,還是原來的”你好“,而如果以gbk方式解碼則出現了三個亂碼字符,為什么是3個而不是2個呢,6/2=3。
接下來說iso-8859-1,這種編碼應用于英文系列,也就是說不能表示中文(如果要使用必須依賴于其它兼容iso-8859-1編碼方式的編碼),它讀不懂的字符都將被視為英文問號'?',英文問號的iso-8859-1編碼號是:63(十進制)(其實在幾乎所有的編碼方式中,所有英文字符都用1個固定的字節碼表示,unicode編碼除外)。
@Test
public void testISO() throws Exception {
String str = "你好";
byte[] bs = str.getBytes("iso-8859-1");
for (byte b : bs) {
System.out.println(b);
}
System.out.println(new String(bs,"iso-8859-1"));
System.out.println(new String(bs,"utf-8"));
System.out.println(new String(bs,"gbk"));
System.out.println(new String(bs,"unicode"));
}
打印結果
63
63
??
??
??
?
說明63 =》?,所有中文都被認為是?,所以說當執行這句代碼時:byte[] bs = "你好".getBytes("iso-8859-1");信息已丟失。
再執行String str = new String(bs,"任何charset");str已經不等于"你好"了,而是兩個問號??。所以在tomcat中我們會經常遇上中文變為一長串??????,就是源于此。
在iso-8859-1、utf-8、gbk中一個字節碼表示一個英文字符,
在unicode編碼中一個字節碼并不能表示任何字符,而且規定必須是兩個字節碼(有時4個)才能表示一個字符。
說了這么多,也許很多人會問為什么要用這么多編碼方式,統一成utf-8不就能表示所有字符了?
編碼不僅僅是要考慮是否能表示任何字符,還要考慮傳輸和存儲。
1、utf-8確實幾乎能表示所有已知字符。前面說過在utf-8編碼中3個字節才表示一個中文字符,這樣顯然占空間,不利于傳輸和存儲(傳輸和存儲都是以二進制的方式進行的)
2、無疑一個字節表示一個字符最省空間,比如iso-8859-1。但這世上不是只有英文字符,還有各個地區國家的文字。所以字符的數量肯定是大于2的8次方的。
所以結合以上兩點,就自然地出現了很多種編碼方式。
以上就是“web前端中文亂碼是怎么產生的”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。