“錕斤拷” 22 元一盒?聊聊它的前世今錕斤拷
不管是在工作中還是生活中,相信很多同學(xué)都被“錕斤拷”深深的毒害過(guò),比如這樣,
這樣,
還有這樣,
那么究竟是為什么會(huì)出現(xiàn)這些奇怪的字符?接下來(lái)我們一探究竟!
ASCII編碼
在計(jì)算機(jī)底層都是用0和1進(jìn)行存儲(chǔ)的,ASCII編碼將所有的字母及符號(hào)進(jìn)行編碼后轉(zhuǎn)成二進(jìn)制的0和1進(jìn)行存儲(chǔ),字母和符號(hào)占1個(gè)字節(jié)(即8bit),標(biāo)準(zhǔn)的ASCII碼規(guī)定最高位必須為0,因此ASCII編碼只能有128個(gè),轉(zhuǎn)成十進(jìn)制即為0-127。標(biāo)準(zhǔn)的ASCII碼表如下:
ASCII碼表只有128個(gè)字符,對(duì)于英語(yǔ)來(lái)說(shuō)已經(jīng)夠用了,但是世界上還有很多國(guó)家的文字各不相同,這時(shí)候就需要一個(gè)更加全面的編碼出現(xiàn)。
Unicode(又稱(chēng)統(tǒng)一碼、萬(wàn)國(guó)碼、單一碼)是計(jì)算機(jī)科學(xué)領(lǐng)域里的一項(xiàng)業(yè)界標(biāo)準(zhǔn)。它為每種語(yǔ)言中的每個(gè)字符設(shè)定了統(tǒng)一并且唯一的二進(jìn)制編碼。在表示一個(gè)Unicode的字符時(shí),通常會(huì)用“U+”然后緊接著一組十六進(jìn)制的數(shù)字來(lái)表示這個(gè)字符。
UTF-8與GBK
UTF-8是針對(duì)Unicode的一種可變長(zhǎng)度字符編碼。它可以用來(lái)表示Unicode標(biāo)準(zhǔn)中的任何字符,而且其編碼中的第一個(gè)字節(jié)仍與ASCII相容。UTF-8使用一至四個(gè)字節(jié)為每個(gè)字符進(jìn)行編碼。常用的漢字采用3個(gè)字節(jié)進(jìn)行編碼。
因?yàn)閁TF-8是針對(duì)Unicode的一種可變長(zhǎng)度的字符編碼,所以它包含了世界上所有字符的編碼,對(duì)于那些早錄入的字符,就會(huì)優(yōu)先使用1、2個(gè)字節(jié)來(lái)存儲(chǔ),對(duì)于遲錄入的字符存儲(chǔ)占用的字節(jié)就會(huì)大一些,這樣,那些遲錄入的字符存儲(chǔ)空間就會(huì)很大。
對(duì)于一個(gè)中文網(wǎng)站,實(shí)際上并不需要其他國(guó)家的文字出現(xiàn),但是中國(guó)漢字用UTF-8進(jìn)行編碼,大多數(shù)卻占用了3個(gè)字節(jié)甚至更多字節(jié),這樣就造成了不必要的存儲(chǔ)浪費(fèi)。為了解決這種問(wèn)題,中華人民共和國(guó)全國(guó)信息技術(shù)標(biāo)準(zhǔn)化技術(shù)委員會(huì)制定了一套GB系列的編碼,最常用的就是GBK了。
GBK編碼英文使用單字節(jié)編碼,完全兼容ASCII字符,漢字使用了兩個(gè)字節(jié)進(jìn)行編碼,其編碼范圍從0x8140(表示16進(jìn)制)至0xFEFE(剔除xx7F),共23940個(gè)碼位,共收錄了21003個(gè)漢字,圖形符號(hào) 883 個(gè)。
為什么要剔除xx7F,因?yàn)樗鼘?duì)應(yīng)的ASCII碼表是DEL,意味著要向后刪除一個(gè)字符。
為什么會(huì)出現(xiàn)“錕斤拷”
Unicode編碼一直持續(xù)在收錄各種字符,這就可能會(huì)出現(xiàn)各種操作系統(tǒng)支持的Unicode字符不一樣。這也就會(huì)導(dǎo)致A上的一個(gè)用Unicode編碼的字符,在B上就會(huì)出現(xiàn)無(wú)法顯示的情況。為了避免這種情況,在Unicode中定義了一個(gè)特殊字符?,它的Unicode編碼為0xFFFD。
假如A支持特殊字符?,但是B并不支持這個(gè)?,那么在B中將會(huì)用?來(lái)代替。
這個(gè)字符用UTF-8編碼后,十六進(jìn)制表示為0xEF 0XBF 0XBD。如果連續(xù)出現(xiàn)兩個(gè)?符號(hào),那么用UTF-8編碼后的十六進(jìn)制則表示為0xEF 0XBF 0XBD 0xEF 0XBF 0XBD,這時(shí)候再轉(zhuǎn)碼成GBK,因?yàn)镚BK中用兩個(gè)字節(jié)表示一個(gè)字符,那么上述的字符就成了錕(0xEFBF),斤(0xBDEF),拷(0xBFBD)。出現(xiàn)錕斤拷的原因就是UTF-8轉(zhuǎn)碼GBK的過(guò)程中出現(xiàn)了問(wèn)題。當(dāng)然如果想要出現(xiàn)錕斤拷,則至少需要兩個(gè)字符出現(xiàn)亂碼。
接下來(lái),我們直接用代碼來(lái)看一下效果:
- @Test
- void contextLoads() throws Exception {
- String str = "�";
- String strCode = new String(str.getBytes("UTF-8"), "GBK");
- System.out.println(strCode);
- }
運(yùn)行結(jié)果為錕?,前面也說(shuō)了如果想要出現(xiàn)錕斤拷,則至少需要為兩個(gè)字符,現(xiàn)在再修改一下代碼。
- @Test
- void contextLoads() throws Exception {
- String str = "��";
- String strCode = new String(str.getBytes("UTF-8"), "GBK");
- System.out.println(strCode);
- }
運(yùn)行結(jié)果如下為錕斤拷。
如果以后再遇到錕斤拷,不要慌,它一定是UTF-8在轉(zhuǎn)換GBK編碼的時(shí)候出現(xiàn)了問(wèn)題?,F(xiàn)在看來(lái)GBK編碼雖然減少了內(nèi)存的浪費(fèi),但是也帶來(lái)了不少問(wèn)題。
本文轉(zhuǎn)載自微信公眾號(hào)「Java旅途」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java旅途公眾號(hào)。