計算機編碼基礎

     亂碼是我們在日常的工作中經常遇到的問題,你可能從網上好不容易下載了一個炫酷的jQuery插件,但是卻在打開的時候,發現某幾個js文件都是類似“澶у0?閬?”這樣的怪異符號,其實這就是編碼和解碼不一致導致的,就好像我用英文給你寫了篇信,你不懂英文用中文去解析它,自然覺得他是亂碼。
     本篇文章將會從計算機碼的歷史演變開始,簡單介紹下主流的幾種編碼方式。希望對大家日後處理亂碼有所幫助。

     一、爲何需要編碼
          由於計算機只能識別0和1,所以我們所有得字符和數據都是轉換成二進制0和1的序列存放在計算機中的,但是我們在如何區分他們上產生了問題。就比如說,給一萬個二進制的序列,你能讀取出來其中哪些是字母哪些是數字麼?不是不可以,難度很大,完全違背了我們使用計算機的初衷了。於是,我們可以規定每個字符的二進制序列,並把它存在計算機內,當需要將二進制位轉換成我們能看懂的字符數據時,讓計算機去截取二進制位查找對應的表,翻譯成我們看的懂的數據。這規定字符的二進制序列就是一種編碼行爲,讓計算機翻譯就是一種解碼行爲。

     二、ASCll 編碼
          我們都知道,計算機是美國人民發明的,所以他們在設計計算機編碼的時候並沒有考慮到給別的國家人用(尤其是我們第三世界國家人民)。ASCll 碼全稱是 American Standard Code for Information,美國信息互換標準代碼。由於美帝人民使用26個英文字母的各種組合進行交流了(沒有我們幾萬漢字那麼多),於是他們使用八位二進制來表示所有的字符,從0到32用於特殊用途,比如:遇上00x10輸出換行,遇上0x1b打印機工作等。還有一些空格,數字,字母等,一直編號到127(0111 1111),實際上他們只用了7個字節編完了所有的字符,因爲最高位始終爲0。

     三、ISO 8859-1/Windows-1252
          對於美國來說ASCll碼足夠用了,但是後來歐洲的一些國家也開始使用計算機,他們也爲自己國家的語言進行擴充編碼,於是他們將美國沒用完的那個字節的後一半用來編碼自己國家的語言,於是從128到255都有了定義。這一段編碼我們叫做擴展字符集。ISO 8859-1就是這樣的編碼標準,0-127依然保存美帝的編碼,128-255編碼了一些他們需要使用到的字符。因爲ISO 8859-1編碼標準出現的比較早,而在後來又出現了一些比較中要的符號例如(歐元符號),這些符號並沒有被編入,於是Windows-1252編碼擴充了ISO 8859-1編碼標準,刪除了一些相對不常用的字符,替換了一些新的字符。可以說Windows-1252是ISO 8859-1的替代品。

     四、GB2312
          終於輪到我們偉大的中國人民,當我們能夠使用計算機的時候,那一個字節已經被使用完了。於是我們決定保留美國的編碼(ASCll 碼),其餘歐洲國家的編碼全部刪除,對於英文和西歐字符使用一個字節足夠用了,對於我們漢字來說,需要使用兩個字節來表示。小於127的依然表示原來的字符(也就是該字節最高位爲0),當計算機遇到兩個大於127的字節時候(也就是兩個字節的最高位都是1),就一次性讀取兩個字節,將它解碼成一個漢字。這就是GB2312編碼,它大概能夠表示7000多個簡體漢字。不包括一些繁體字,但是對於日常使用已經足夠。在這兩個字節中,高位字節表示範圍:0xA1-0xF7,低字節爲表述範圍:0xA1-0xFE。(可能大家看出來,有些範圍並沒有定義編碼,後面說原因)

     五、GBK
          雖然已經編碼了7000多個漢字,足夠日常的使用了,但是我們勤勞的中國人民還是覺得不夠用,於是他們發現:一個漢字使用兩個字節表示,那如果第一個字節的最高位爲1,那就不用將後一個字節的最高位也置爲1,直接往後讀取兩個字節就好了。於是我們又擴充了一半的漢字。高位字節表述範圍:0x81-0xFE,低位字節表述範圍:0x40-0x7E和0x80-0xFE。

     六、GB18030
          爲了照顧日韓和我們的少數民族,我們又對GBK加以擴充,使用變長編碼,要麼使用兩個字節表示要麼用四個字節表示。(至於爲什麼三個字節不用來表示,我也費解)那麼我們怎麼才能判斷出某個字符他是用幾個字節來表示的呢?用兩個字節表示的字符和GBK一樣,用四個字節表示的字符,第一個字節表述範圍:0x81-0xFE,第二個字節表述的範圍:0x30-0x39,第三個字節表述的範圍:0x81-0xFE,第四個字節表述範圍:0x30-0x39。每次解析的時候先拿過來這個字符的第二個字節判斷範圍是否在0x30-0x39之間,如果在說明這是四個字節表示的字符,如果不在說明這是兩個字節表示的字符。從GBK的第二個字節表述範圍看,它是大於0x39的。(這就是它低位字節0x30-0x39不編碼的原因)

     七、Unicode
          每個國家都按照自己的標準編碼的字符集,但是這會導致一個問題,兩個編碼不一致的國家的人相互之間交流成了很大的問題。(除了美國可以和任意的國家無障礙交流,因爲每個編碼標準都是兼容ASCll 的),於是當人們需要和別的國家之間進行交流的時候,就會在自己的系統上裝上一個對方國家的編碼轉換系統。十分麻煩。於是 一個叫ISO(國際標誰化組織)的組織打算對世界上的所有編碼進行統一,廢除所有地方性編碼方案。這就是UNICODE。所以,準確上來說UNICODE並不算是一種具體的編碼標準,它只是將世界上所有的字符進行的編號,並沒有指定他們具體在計算機中以什麼樣的形式存儲。
          不像上述的各種編碼標準,準確的規定了每個字符在計算機中的二進制位,而UNICODE只是將所有的字符進行了編號,具體怎麼存儲它不關心。於是它有了幾個具體的實現:UTF-8,UTF-32,UTF-16等。UNICODE的編號範圍爲:0x000000-0x10FFFF,包括將近110多萬。基本囊括所有的字符,但是經常使用的範圍在:0x0000-0xFFFF之間也就是65536以內。

     UTF-32
       UTF-32編碼標準用固定4個字節進行編碼。每個字符會有一個對應的Unicode編號,這個編號是個整數,它的二進制就是這個字符UTF-32編碼。四個字節足夠表示世界上的所有的字符,但是對於只需要的一個字節的ASCll 編碼的字符也是使用了四個字節(浪費了三個字節),所以這種編碼標準唯一的缺點就是浪費。一個概念,"大端"和"小端"。大端表示的是:四個字節序列,高字節在前,低字節在後。(也就是計算機讀取順序從前到後),小端則相反,將低字節排列在前面。這種編碼方式缺點是很明顯的,就是浪費空間,但是簡單。

     UTF-16
       UTF-16使用的是變長字節表示,相對複雜些。分別使用兩個字節或者四個字節表示。編號在 0x0000-0xFFFF之間的常用字符使用兩個字節表示,其中0xD800-0xDBFF之間的編號沒有定義字符。(用於辨別兩個字節還是四個字節和GB18030類似)對於編號在0x10000-0x10FFFF之間的字符使用四個字節表示。只不過前兩個字節被叫做高代理項後兩個字節被稱爲低代理項,其中高代理項表述範圍:0xD800-0xDBFF正好是上面沒有定義的編號範圍,低代理項表述範圍:0xDC00-0xDFFF。區分一個字符是用的兩個字節還是用的四個字節就不言而喻了。直接判斷前兩個字節的範圍即可。
       這種編碼標準相對於UTF-32來說,是節約了不少空間,但是對於美國和西歐他們來說還是有點浪費。這種編碼一般用於系統編碼。

     UTF-8
       爲了充分利用資源,還是被我們智慧的人類發明了UTF-8。UTF-8使用變長字節表示,分別可以使用1到4個字節不等,對於Unicode編號越小的自然使用的字節就越小。
這裏寫圖片描述
       可以看到編號在127以內的使用一個字節表示(也就是ASCll ),(128-2047)使用兩個字節表示,(2048-65535)使用三個字節表示,也就是我們大部分的漢字都是使用三個字節表示的,(65536以上)使用四個字節表示。
       不同的區間範圍對應了不同的模板。對於一個字符拿到Unicode編號之後,轉換成而二進制判斷所屬範圍,使用模板編碼(具體怎麼編碼馬上說)。除了用ASCll碼的字符們,其他字符的模板的第一個字節都n個1加一個0,表示什麼意思呢?第一個字節有幾個1表示此字符由幾個字節表示,方便計算機讀取,低位字節開頭都是10。 下面看一個例子:漢字“馬”的Unicode編號是0x9A6C,轉換成整數是39532,對應的模板是:1110xxxx 10xxxxxx 10xxxxxx。將整數39532轉換成二進制:1001 1010 0110 1100。將這個二進制位從右向左開始,一次填入模板中x中,得到如下結果:1110 1001 1010 1001 1010 1100 1110。這就是“馬”字的UTF-8編碼。計算機解碼的時候會一次性讀取三個字節,逆操作解碼,查表顯示漢字。

     最後小結一下,對於之前的一些編碼標準都是按照編號轉爲二進制來形成編碼,GB18030使用變長字節表示,通過比較任意字符的第二個字節的範圍來判斷存儲時使用的字節數。UTF-16也是一種變長字節表示方案,通過比較高代理項的範圍來確定使用字節數。UTF-8編碼方式可以說是將上面的兩種編碼方式的有點擴充到了極致,使用變長字節表示,但是通過使用模板的方式來區分1-4個字節長度。只是過程有點複雜,但是綜合還是UTF-8更加令人喜歡。
     個人覺得所有編碼標準應該都廢棄,保留Unicode編碼方式,使得從整個世界的角度上所有編碼是統一的,這樣就會大大減少亂碼出現的頻率。實際上,蘋果早就拋棄所有方言編碼標準,只接受Unicode編碼標準。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章