現(xiàn)在Unicode已然一統(tǒng)天下非洲,我想很多年輕的程序員可能都沒遇到過編碼問題鸭限,更不用說了解編碼的發(fā)展了。前些日子在一個老網(wǎng)站上偶遇亂碼两踏,雖然入行時間不短败京,但對其究竟也是不甚了解,好奇心驅(qū)使下落入深坑梦染。還好經(jīng)過一段時間的摸爬滾打赡麦,邊學(xué)邊寫,總算大概理清了個脈絡(luò)帕识,記錄之泛粹,分享之。
概念
字符是一個信息單位肮疗,在計算機里面晶姊,一個中文漢字是一個字符,一個英文字母是一個字符伪货,一個阿拉伯?dāng)?shù)字是一個字符帽借,一個標(biāo)點符號也是一個字符。
字符集是字符組成的集合超歌,通常以二維表的形式存在,二維表的內(nèi)容和大小是由使用者的語言而定蒂教,是英語巍举,是漢語,還是阿拉伯語凝垛。
字符編碼是把字符集中的字符編碼為特定的二進制數(shù)懊悯,以便在計算機中存儲。編碼方式一般就是對二維表的橫縱坐標(biāo)進行變換的算法梦皮。一般都比較簡單炭分,直接把橫縱坐標(biāo)拼一起就完事了。后來隨著字符集的不斷擴大剑肯,為了節(jié)省存儲空間捧毛,才出現(xiàn)了各種各樣的算法。
字符集和字符編碼一般都是成對出現(xiàn)的,如ASCII呀忧、IOS-8859-1师痕、GB2312、GBK而账,都是即表示了字符集又表示了對應(yīng)的字符編碼胰坟,以后統(tǒng)稱為編碼。Unicode比較特殊泞辐,后面細(xì)說笔横。
發(fā)展
單字節(jié)
計算機是美國人發(fā)明的,人家用的是美式英語咐吼,字符比較少吹缔,所以一開始就設(shè)計了一個不大的二維表,128個字符汽烦,取名叫ASCII(American Standard Code for Information Interchange)涛菠。128個碼位,用7位二進制數(shù)表示撇吞,由于計算機1個字節(jié)是8位二進制數(shù)俗冻,所以最高位為0,即00000000-01111111
或0x00-0x7F
牍颈。
后來美國人發(fā)現(xiàn)128個碼位不夠用迄薄,于是在原來二維表的基礎(chǔ)上進行了擴展,256個字符煮岁,取名叫EASCII(Extended ASCII)讥蔽。256個碼位,用8位二進制數(shù)表示画机,即00000000-11111111
或0x00-0xFF
冶伞。
當(dāng)計算機傳到了歐洲,美國人的標(biāo)準(zhǔn)不適用了步氏,但是改改還能湊合响禽。于是國際標(biāo)準(zhǔn)化組織在ASCII的基礎(chǔ)上進行了擴展,形成了ISO-8859標(biāo)準(zhǔn)荚醒,跟EASCII類似芋类,兼容ASCII,在高128個碼位上有所區(qū)別界阁。但是由于歐洲的語言環(huán)境十分復(fù)雜侯繁,所以根據(jù)各地區(qū)的語言又形成了很多子標(biāo)準(zhǔn),ISO-8859-1泡躯、ISO-8859-2贮竟、ISO-8859-3丽焊、……、ISO-8859-16坝锰,真是令人發(fā)指粹懒。
雙字節(jié)
當(dāng)計算機傳到了亞洲,尤其是東亞顷级,國際標(biāo)準(zhǔn)被秒殺了凫乖,路邊小孩隨便說句話,256個碼位就不夠用了弓颈。于是乎繼續(xù)擴大二維表帽芽,單字節(jié)改雙字節(jié),16位二進制數(shù)翔冀,65536個碼位导街。在不同國家和地區(qū)又出現(xiàn)了很多編碼,大陸的GB2312纤子、港臺的BIG5搬瑰、日本的Shift JIS等等。
注意65536個碼位這種說法只是理想情況控硼,由于雙字節(jié)編碼可以是變長的泽论,也就是說同一個編碼里面有些字符是單字節(jié)表示,有些字符是雙字節(jié)表示卡乾。這樣做的好處是翼悴,一方面可以兼容ASCII,另一方面可以節(jié)省存儲容量幔妨,代價就是會損失一部分碼位鹦赎。而且編碼的設(shè)計也并不是想象的那樣,所有字符從頭到尾布滿整個二維表误堡,都是有預(yù)留空間的古话。比如說GBK是GB2312的擴展(K竟然是拼音KuoZhan的縮寫),按理說都屬于雙字節(jié)編碼锁施,碼位是一樣的煞额,根本談不上擴展,但實際上是預(yù)留空間在起作用沾谜。比如下圖為GBK的編碼空間,GBK/1胀莹、GBK/2是GB2312的區(qū)域基跑,GBK/3、GBK/4描焰、GBK/5是GBK的區(qū)域媳否,紅色是用戶自定義區(qū)域栅螟,白色可能就是由于變長編碼損失的區(qū)域了。
Unicode
當(dāng)互聯(lián)網(wǎng)席卷了全球篱竭,地域限制被打破了力图,不同國家和地區(qū)的計算機在交換數(shù)據(jù)的過程中,就會出現(xiàn)亂碼的問題掺逼,跟語言上的地理隔離差不多吃媒。亂碼是怎么出現(xiàn)的呢?對同一組二進制數(shù)據(jù)吕喘,不同的編碼會解析出不同的字符赘那,用對了編碼,解析出來的字符組成的文字是有意義的氯质,用錯了編碼募舟,解析出來的字符組成的文字是沒意義的,也就是通常所說的亂碼闻察。
經(jīng)過之前的介紹拱礁,編碼很多,全球的計算機們沒辦法在一起好好的玩耍辕漂。要徹底解決這個問題呢灶,替代原先基于語言的編碼系統(tǒng),就需要一個通用的字符集UCS(Universal Character Set)和一個通用的字符編碼Unicode钮热。一開始UCS用2個字節(jié)表示填抬,叫做UCS-2,后來2個字節(jié)不夠用隧期,于是就用4個字節(jié)飒责,叫做UCS-4。但是如果每一個字符都用4個字節(jié)來表示的話仆潮,相較之前的編碼會浪費很多存儲空間宏蛉,尤其是相對ASCII等單字節(jié)編碼會非常吃虧。并且當(dāng)時已經(jīng)有些廠商在雙字節(jié)編碼上投入了很大的精力性置。于是UTF-16就被作為一種折中的方案提了出來拾并,既保持了兩字節(jié)不變,又保證了足夠的編碼空間鹏浅。而UTF-32是與UCS-4相對應(yīng)的嗅义,UTF-8則由于擴展性比較強,從容應(yīng)對了UCS-2到UCS-4的改變隐砸。關(guān)于各種UTF的實現(xiàn)細(xì)節(jié)可以點擊鏈接查看(翻墻)之碗,已經(jīng)說得很清楚了,就不贅述了季希,但不得不提一下褪那,UTF-16的設(shè)計還挺巧妙的幽纷。
UTF(Unicode Transformation Format)是將Unicode編碼進行了轉(zhuǎn)換,通常會在存儲空間和效率上進行一定的權(quán)衡博敬,有很多種實現(xiàn)方式友浸,前面提到了UTF-8和UTF-16是最常用的。這就是之前提到的Unicode的特殊之處偏窝。
歷史
ASCII
1960 開發(fā)
1963 發(fā)布
1986 最后一次更新ISO-8859-1
1998 發(fā)布GB2312
1980 發(fā)布GBK
1993 發(fā)布UCS-2
In the late 1980sUnicode
1987 開發(fā)
1991 發(fā)布
1996 實現(xiàn)代理機制(UTF-16)
2015 最新版8.0UTF-8
1993 發(fā)布
2008 流行UTF-16
1996 開發(fā)
2000 發(fā)布
根據(jù)以上各個編碼發(fā)展的一些時間節(jié)點收恢,再配合下圖UTF-8制霸互聯(lián)網(wǎng)過程,會有一個比較清晰的了解囚枪。
尾聲
雖然Unicode解決了地球上的問題派诬,但是以后三體人入侵可怎么辦,根據(jù)這些天研究編碼發(fā)展歷史來看链沼,比較靠譜的回答——還是到時再說吧默赂。
本文是根據(jù)互聯(lián)網(wǎng)上各種信息來源,主要是維基百科括勺,加上自己的理解缆八,進行的總結(jié)和演繹,肯定有不準(zhǔn)確或錯誤的地方疾捍,還望不吝賜教奈辰。