計算機基礎--什麼是編碼?
作者名:麗斯
什麼是編碼
編碼是信息從一種形式或格式轉換為另一種形式的過程,簡單來講就是語言的翻譯過程。我們都知道計算機使用的是機器語言即二進位碼,相信大部分人都無法流暢的閱讀二進位碼,於是為了能夠讓人類更好的理解計算機輸出的結果就需要將機器語言轉換為自然語言,比如英語、俄語和中文等。 這看似簡單的語言轉換過程隨著計算機的普及與網際網路化對語言字符的編碼衝擊也越來越大,編碼規範的調整也伴隨著整個計算機發展歷史。
現代編碼模型
為了能夠更精確的描述在編碼過程中各個產物的歸屬以便正確的描述產物所發揮的功能,於是多事之人將現代的編碼整理為一套可以說明的模型而且分為五層之多。
現代編碼模型之分層:
1. 抽象字符表(ACR:Abstract character repertoire):是一個系統支持的所有抽象字符的集合,簡單來說就是該層規範要確定一個系統能夠包含的字符和字符形式,比如Windows支持中文,那麼它的抽象字符表一定有中文字符集合而且也適配不同編碼方式指定具體是何字符。
2. 編碼字符集(CCS:Coded Character Set):是將字符集中每個字符映射到1個坐標(整數值對:x, y)或者表示為1個非負整數。字符集及碼位映射稱為編碼字符集。例如,在一個給定的字符表中,表示大寫拉丁字母「A」的字符被賦予整數65、字符「B」是66,如此繼續下去。簡單來說這就是一個映射關係表,將一串碼值映射到抽象字符表裡的特定字符。
3. 字符編碼表(CEF:Character Encoding Form):該層也稱為」storage format」,對於一個包含幾乎全球語言的字符集,比如Unicode字符集最多可以2的31次方個字符,用4個字節來存儲一個,但是真的有必要在時時刻刻都使用4個字節來記錄一個字符嗎?很顯然不是這樣,比如拉丁字母「A」實際上需要二進位碼01000001一個字節就可以表示,於是需要一種類似於壓縮方式的方法來儘量用最少空間存儲不同種類字符的方式比如後面會提到的UTF。所以這一層主要是描述字符編碼所能採用的編碼格式。
4. 字符編碼方案(CES:Character Encoding Scheme):也稱作」serialization format」,將定長的整型值(即碼元)映射到8位字節序列,以便編碼後的數據的文件存儲或網絡傳輸。
5. 傳輸編碼語法(transfer encoding syntax):用於處理上一層次的字符編碼方案提供的字節序列。一般其功能包括兩種:一種是把字節序列的值映射到一套更受限制的值域內,以滿足傳輸環境的限制,例如Email傳輸時 Base64或者quoted-printable,都是把8位的字節編碼為7位長的數據;另一種是壓縮字節序列的值,如 LZW 或者 行程長度編碼等無損壓縮技術。
常用的編碼
ASCII
ASCII(發音: [/ski/]) ,American Standard Code for Information Interchange,美國信息交換標準代碼)是基於拉丁字母的一套計算機編碼系統。它主要用於顯示現代英語,而其擴展版本 EASCII 則可以部分支持其他西歐語言,並等同於國際標準ISO/IEC 646]。 ASCII編碼由1個字節8bit來標識字符編碼表映射關係,如果按字節來算最多支持256個字符映射,但是由於最高位始終為0,支持的字符更少了。下圖為編碼表:
從圖中可以看到,如果使用ASCII碼錶,將二進位高四位(0100)低四位 (0001)對應ASCII碼錶就得到了A字符,如果要得到I LOVE Y,計算機只需要得到二級制01001001(I)00100000(空格)01001100(L)01001111(O)01010110(V)01000101(E)00100000(空格)01011001(Y)。 ASCII碼所對應的所有字符高四位首位都為0,所以ASCII碼成功的用7個比特位就完成了計算機語言轉換為自然語言(人類語言)的壯舉,這看起來很令人振奮,美國人天真的以為IPv4的最大數255.255.255.255(32位)總計4,294,967,296個地址(其中還有些專用地址佔去一小部分)就能覆蓋全球的網絡設備。所以說當其他國家的語言比如中文、日文和阿拉伯文需要用計算機顯示的時候就完全無法使用ASCII碼如此少量的編碼映射方式。
GB2312
1974年8月,中國開始了748工程,包括了用計算機來處理中文字,展開了各種研究工作,後來到1980年公布了 GB 2312-80漢字編碼的國家標準。 GB 2312標準共收錄6763個漢字 ,其中一級漢字3755個, 二級漢字3008個;同時收錄了包括 拉丁字母、 希臘字母、 日文、平假名及片假名字母、 俄語在內的682個字符。 看起來GB2312已經很牛逼了,使用2個字節作為編碼字符集的空間,但是6763個漢字是真的不夠用啊。
GBK
我漢語博大精深,只有6763個字怎麼夠?於是GBK中在保證不和GB2312、ASCII衝突(即兼容GB2312和ASCII)的前提下,也用每個字佔據2位元組的方式又編碼了許多漢字。經過GBK編碼後,可以表示的漢字達到了20902個,另有984個漢語標點符號、部首等。值得注意的是這20902個漢字還包含了繁體字。
GB18030
然而,GBK的兩萬多字也已經無法滿足我們的需求了,還有更多可能你自己從來沒見過的漢字需要編碼。這時候顯然只用2位元組表示一個字已經不夠用了(2位元組最多只有65536種組合,然而為了和ASCII兼容,最高位不能為0就已經直接淘汰了一半的組合,只剩下3萬多種組合無法滿足全部漢字要求)。因此GB18030多出來的漢字使用4位元組編碼。當然,為了兼容GBK,這個四字節的前兩位顯然不能與GBK衝突(實操中發現後兩位也並沒有和GBK衝突)。我國在2000年和2005年分別頒布的兩次GB18030編碼,其中2005年的是在2000年基礎上進一步補充。至此,GB18030編碼的中文文件已經有七萬多個漢字了,甚至包含了少數民族文字。
Unicode
在ASCII編碼明顯不夠用後,美國國家標準學會又搞了幾套ISO的編碼規範來兼容其他中歐等國家的語言,但是兼容性還是有不少問題。最終美國加州的Unicode組織他們放大招搞了Unicode(萬國碼)打算藉此一統江湖,最早Unicode也是最高16位2位元組來進行映射,經過幾番修改最終可以以最長32位4位元組的空間來映射最多2的31次方個字符。看起來一切完美了,當然如果以後有了星際旅行並不一定能夠完全標識全宇宙的文字。
從上面這一大堆改動來看,不管中國還是美國,在處理位數上遠遠低估了後續可能產生的擴展性,你可能會覺得一早就用4個字節來標識全球所有字符就完事了費那麼大勁來回改。給你看一幅圖你或許就會明白為什麼那時候的科學家那麼謹小慎微了。如圖:
1956年IBM的硬碟,可存儲5MB的數據
UTF-8又是什麼
Unicode確實是一套能夠滿足全球使用的字符集,但是難道真的需要每一個字符都佔用4個字節嗎?雖然現在的存儲空間已經足夠大了,但是4個字節一個字符的方式還是很不明智的,比如字符「A」二進位碼01000001卻需要以00000000000000000000000001000001的方式存儲。這一定不是我們想要的。於是UTF(Unicode/UCS Transformation Format)應運而生,UTF是字符編碼五層次模型的第三層,通過特定的規則對Unicode字符編碼進行一定的壓縮和轉換以便快捷傳輸。 UTF的代表就是UTF-16和UTF-8,千萬不要以為UTF-16比UTF-8更厲害能夠容納更多字符,字符容納數量都是是Unicode編碼集所確定的範圍,UTF只是通過不同的轉換形式更快更高效的找到特定字符。而UFT-16 比較奇葩,它使用 2 個或者 4 個字節來存儲。 對於 Unicode 編號範圍在 0 ~ FFFF 之間的字符,UTF-16 使用兩個字節存儲,並且直接存儲 Unicode 編號,不用進行編碼轉換,這跟 UTF-32 非常類似。 對於 Unicode 編號範圍在 10000~10FFFF 之間的字符,UTF-16 使用四個字節存儲,具體來說就是:將字符編號的所有比特位分成兩部分,較高的一些比特位用一個值介於 D800~DBFF 之間的雙字節存儲,較低的一些比特位(剩下的比特位)用一個值介於 DC00~DFFF 之間的雙字節存儲。
設計UTF-8編碼表達方式的理由:
1、單字節字符的最高有效比特永遠是0(大家可以看看其他編碼方式如何彆扭的兼容ASCII碼的);
2、多字節序列中的首個字符組的幾個最高有效比特決定了序列的長度。最高有效位為110的是2位元組序列,而1110的是三字節序列,如此類推;
3、多字節序列中其餘的字節中的首兩個最高有效比特為10。
轉換關係如下圖:
這樣我們根據所要兼容的語言不同根據UTF-8多字節最高有效比特去判斷編碼最終使用了多少個字節來存儲,其餘的字節也都滿足最高有效比特為10的特點有了一定的糾錯功能。 簡單一些理解就是UTF-16就是通過2個字節16位來控制壓縮比例,而UTF-8已經以高精度的1個字節8位來控制壓縮比例了。當然還有中UTF-32就可想而知,基本跟Unicode如出一轍。