不管是在工作中還是生活中,相信很多同學都被“錕斤拷”深深的毒害過,比如這樣,
這樣,
還有這樣,
那么究竟是為什么會出現這些奇怪的字符?接下來我們一探究竟!
ASCII編碼
在計算機底層都是用0
和1
進行存儲的,ASCII編碼將所有的字母及符號進行編碼后轉成二進制的0
和1
進行存儲,字母和符號占1個字節(即8bit),標准的ASCII碼規定最高位必須為0
,因此ASCII編碼只能有128個,轉成十進制即為0-127。標准的ASCII碼表如下:
ASCII碼表只有128個字符,對於英語來說已經夠用了,但是世界上還有很多國家的文字各不相同,這時候就需要一個更加全面的編碼出現。
Unicode(又稱統一碼、萬國碼、單一碼)是計算機科學領域里的一項業界標准。它為每種語言中的每個字符設定了統一並且唯一的二進制編碼。在表示一個Unicode的字符時,通常會用“U+”然后緊接着一組十六進制的數字來表示這個字符。
UTF-8與GBK
UTF-8
是針對Unicode
的一種可變長度字符編碼。它可以用來表示Unicode
標准中的任何字符,而且其編碼中的第一個字節仍與ASCII相容。UTF-8使用一至四個字節為每個字符進行編碼。常用的漢字采用3
個字節進行編碼。
因為UTF-8
是針對Unicode
的一種可變長度的字符編碼,所以它包含了世界上所有字符的編碼,對於那些早錄入的字符,就會優先使用1、2個字節來存儲,對於遲錄入的字符存儲占用的字節就會大一些,這樣,那些遲錄入的字符存儲空間就會很大。
對於一個中文網站,實際上並不需要其他國家的文字出現,但是中國漢字用UTF-8
進行編碼,大多數卻占用了3
個字節甚至更多字節,這樣就造成了不必要的存儲浪費。為了解決這種問題,中華人民共和國全國信息技術標准化技術委員會制定了一套GB系列的編碼,最常用的就是GBK
了。
GBK
編碼英文使用單字節編碼,完全兼容ASCII字符,漢字使用了兩個字節進行編碼,其編碼范圍從0x8140(表示16進制)至0xFEFE(剔除xx7F),共23940個碼位,共收錄了21003個漢字,圖形符號 883 個。
為什么要剔除xx7F
,因為它對應的ASCII碼表是DEL
,意味着要向后刪除一個字符。
為什么會出現“錕斤拷”
Unicode編碼一直持續在收錄各種字符,這就可能會出現各種操作系統支持的Unicode字符不一樣。這也就會導致A上的一個用Unicode編碼的字符,在B上就會出現無法顯示的情況。為了避免這種情況,在Unicode中定義了一個特殊字符�,它的Unicode編碼為0xFFFD。
假如A支持特殊字符⬆
,但是B並不支持這個⬆
,那么在B中將會用�來代替。
這個字符用UTF-8編碼后,十六進制表示為0xEF 0XBF 0XBD。如果連續出現兩個⬆
符號,那么用UTF-8編碼后的十六進制則表示為0xEF 0XBF 0XBD 0xEF 0XBF 0XBD,這時候再轉碼成GBK,因為GBK中用兩個字節表示一個字符,那么上述的字符就成了錕(0xEFBF),斤(0xBDEF),拷(0xBFBD)。出現錕斤拷的原因就是UTF-8轉碼GBK的過程中出現了問題。當然如果想要出現錕斤拷,則至少需要兩個字符出現亂碼。
接下來,我們直接用代碼來看一下效果:
@Test
void contextLoads() throws Exception {
String str = "�";
String strCode = new String(str.getBytes("UTF-8"), "GBK");
System.out.println(strCode);
}
運行結果為錕�
,前面也說了如果想要出現錕斤拷,則至少需要為兩個字符,現在再修改一下代碼
@Test
void contextLoads() throws Exception {
String str = "��";
String strCode = new String(str.getBytes("UTF-8"), "GBK");
System.out.println(strCode);
}
運行結果如下為錕斤拷
。
如果以后再遇到錕斤拷,不要慌,它一定是UTF-8在轉換GBK編碼的時候出現了問題。現在看來GBK編碼雖然減少了內存的浪費,但是也帶來了不少問題。
參考:zhihu.com/question/23024782
點關注、不迷路
如果覺得文章不錯,歡迎關注、點贊、收藏,你們的支持是我創作的動力,感謝大家。
如果文章寫的有問題,請不要吝嗇,歡迎留言指出,我會及時核查修改。
如果你還想更加深入的了解我,可以微信搜索「Java旅途」進行關注。回復「1024」即可獲得學習視頻及精美電子書。每天7:30准時推送技術文章,讓你的上班路不在孤獨,而且每月還有送書活動,助你提升硬實力!