天天看點

字元集和編碼方式

位元組

位元組是計算存儲容量的一種計量機關。因為計算機隻能識别1和0組成的二進制位,一個數就是1位(bit),8位就是一個位元組。

例如 :00001111 這個8位二進制數就占了一個位元組的存儲容量。

字元

任何一個文字或符号都是一個字元,但所占位元組不一定,不同的編碼導緻一個字元所占的記憶體不同。

例如:标點符号‘+’是一個字元,漢字‘我們’是兩個字元,在GBK編碼中一個漢字占2個位元組,在UTF-8編碼中一個漢字占3個位元組。

編碼規範

程式員們希望在計算機中顯示字元,但計算機隻能識别0和1的二進制數,于是國際組織就制定了編碼規範,希望使用不同的二進制數來表示不同的字元,這樣計算機就可以根據二進制數來顯示其對應的字元。

例如:GBK 編碼規範,計算機可以在中文字元和二進制數之間互相轉換,而使用GBK編碼也就可以使計算機顯示中文字元。

  • 字庫表

    一套編碼規範不一定包含世界上所有的字元,每套編碼規範都有自己的使用場景。而字庫表就存儲了編碼規範中能顯示的所有字元,計算機根據二進制數從字庫表中找到字元然後顯示給使用者,相當于一個存儲字元的資料庫。

    例如:幾乎所有漢字都儲存在GBK 編碼規範的字庫表中,是以計算機可以顯示漢字,但法語,俄語并不在其字庫表中,是以GBK不能顯示法語,俄語等不包含在其中的字元。

  • 字元集

    在一個字庫表中,每一個字元都有一個對應的二進制位址,而字元集就是這些位址的集合。

    例如:在ASCII編碼字元集中,字母A的序号(位址)是65,65的二進制就是01000001。我們可以說編碼字元集就是用來存儲這些二進制數的,而這個二進制數就是編碼字元集中的一個元素,同時它也是字庫表中字母A的位址,我們根據這個位址就可以顯示出字母A。

  • 編碼方式

    直接使用字元對應的二進制位址來顯示文字是十分浪費的,Unicode 編碼規範中包括了幾百萬個字元,起碼需要3個位元組的容量,為了友善将來擴充Unicode還保留了更多未使用的空間,最多可以存儲4個位元組的容量。

    是以為了區分每個字元,哪怕是00000000 00000000 00000000 00001111這種其實隻占了1個位元組的字元,也要為他配置設定4個位元組的空間,這就導緻一個可以用1G儲存的檔案,現在需要4G才能儲存,這是極其浪費的做法。

    于是程式員制定了一套算法來節省空間,而每種不同的算法都被稱作一種編碼方式。一套編碼規範可以有多種不同的編碼方式,不同的編碼方式有不同的适應場景。

    例如:UTF-8就是一種編碼方式,Unicode是一種編碼規範。此外,Unicode還有UTF-16,UTF-32的編碼方式,不同的編碼方式節約的空間不同。

    一個較短的二進制數,通過一種編碼方式,轉換成編碼字元集中正常的位址,然後在字庫表中找到一個對應的字元,最終顯示給使用者。

常見編碼方式

  • ASCII

    ASCII碼,是最早産生的編碼規範,一共包含00000000~01111111共128個字元,可以表示阿拉伯數字和大小寫英文字母,以及一些簡單的符号。ASCII碼隻需要1個位元組的存儲空間,最高位為0。它沒有特定的編碼方式,直接使用位址對應的二進制數來表示。

  • GBK

    GBK支援國際标準ISO/IEC10646-1和國家标準GB13000-1中的全部中日韓漢字。GBK字元集中所有字元占2個位元組,不論中文英文都是2個位元組。 沒有特殊的編碼方式,一般在國内,漢字較多時使用。

  • ISO-8859-1

    ISO-8859-1收錄的字元除ASCII收錄的字元外,還包括西歐語言、希臘語、泰語、阿拉伯語、希伯來語對應的文字元号。因為ISO-8859-1編碼範圍使用了單位元組内的所有空間,在支援ISO-8859-1的系統中傳輸和存儲其他任何編碼的位元組流都不會被抛棄。換言之,把其他任何編碼的位元組流當作ISO-8859-1編碼看待都沒有問題。這是個很重要的特性,MySQL資料庫預設編碼是Latin1就是利用了這個特性。ASCII編碼是一個7位的容器,ISO-8859-1編碼是一個8位的容器。ISO-8859-1隻占1個位元組,且MySQL資料庫預設編碼就是ISO-8859-1。

  • Unicode

    從以上幾種編碼規範可以看出,各種編碼規範互不相容,且隻能表示自己需要的字元,于是,國際标準化組織(ISO)決定制定一套全世界通用的編碼規範Unicode。

    Unicode包含了全世界所有的字元。Unicode最多可以儲存4個位元組容量的字元。也就是說,要區分每個字元,每個字元的位址需要4個位元組。這是十分浪費存儲空間的,于是,程式員就設計了幾種字元編碼方式,比如:UTF-8,UTF-16,UTF-32。

    最廣為程式員使用的就是UTF-8,UTF-8是一種變長字元編碼,注意:UTF-8不是編碼規範,而是編碼方式。

    編碼規則表

    字元集和編碼方式

    如上表所示,對于隻需要1個位元組的字元,UTF-8采用ASCII碼的編碼方式,最高位補0來表示。

    例如:01000001我們就是用01000001來表示,對于一個位元組的字元,其實就是直接使用位址表示。

    而對于n個位元組的字元(n>1),即大于一個位元組的字元,采用第一個位元組前n位補1。第n+1位填0,後面位元組的前兩位一律設為10。剩下的沒有提及的二進制位,全部為這個符号的unicode碼。

    例如:漢字嚴的Unicode碼是4E25轉換成二進制就是01001110 00100101共15位,根據上表可知使用UTF-8字元編碼後占3個位元組,是以前3位是1,第4位(n+1位)是0,後面兩個位元組中每個位元組的前兩位都是10,即1110 xxxx 10 xxxxxx 10xxxxxx。填充進去後就變成了1110 0100 10 111000 10 100101共計24位占3個位元組。

    由此可見,英文在UTF-8字元編碼後隻占1個位元組,中文占了3個位元組。

    雖然UTF-8編碼沒有GBK編碼占的空間小,但它勝在面向全世界,至于使用哪一種編碼還是取決于具體的使用環境。

編碼與解碼

一串二進制數,使用一種編碼方式,轉換成字元,這個過程我們稱之為解碼。使用錯誤的編碼方式,産生其他不合理的字元,這就是我們通常說的亂碼。

一串已經解碼後的字元,我們也可以選用任意類型的編碼方式重新轉換成一串二進制數,這個過程就是編碼。無論使用哪一種編碼方式進行編碼,最終都是産生計算機可識别的二進制數,但如果編碼規範的字庫表不包含目标字元,則無法在字元集中找到對應的二進制數。這将導緻不可逆的亂碼!例如:像ISO-8859-1的字庫表中不包含中文,是以哪怕将中文字元使用ISO-8859-1進行編碼,再使用ISO-8859-1進行解碼,也無法顯示出正确的中文字元。

繼續閱讀