01 字符編碼入門講解

一、基礎概念

字節

這個是最基本的概念了,字節是計算存儲容量的一種計量單位。我們知道計算機只能識別1和0組成的二進制位。一個數就是1位(bit),爲了方便計算,我們規定8位就是一個字節

例如 :00001111 這個8位二進制數就佔了一個字節的存儲容量。

字符

字符和字節不太一樣,任何一個文字或符號都是一個字符,但所佔字節不一定,不同的編碼導致一個字符所佔的內存不同。

例如:標點符號+是一個字符,漢字我們是兩個字符,在GBK編碼中一個漢字佔2個字節,在UTF-8編碼中一個漢字佔3個字節。

隨着時代的發展,程序員們希望在計算機中顯示字符,但計算機只能識別0和1的二進制數。於是就有了編碼規範。

編碼規範

所謂字符集其實是一套編碼規範中的子概念,爲了顯示字符,國際組織就制定了編碼規範,希望使用不同的二進制數來表示代表不同的字符,這樣電腦就可以根據二進制數來顯示其對應的字符。我們通常就稱呼其爲XX編碼,XX字符集。

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

接下來爲大家介紹一下編碼規範裏的3個子概念。

字庫表

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

例如:幾乎所有漢字都保存在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。後被稱爲(American Standard Code for Information Interchange,美國信息交換標準代碼)。它沒有特定的編碼方式,直接使用地址對應的二進制數來表示,非要說那就叫他ASCII 編碼方式。

GBK

GBK全稱《漢字內碼擴展規範》,支持國際標準ISO/IEC10646-1和國家標準GB13000-1中的全部中日韓漢字。GBK字符集中所有字符佔2個字節,不論中文英文都是2個字節。 沒有特殊的編碼方式,習慣稱呼GBK 編碼。一般在國內,漢字較多時使用。

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,有時,tomcat服務器默認也是使用ISO-8859-1編碼,然而ISO-8859-1是不支持中文的,有時這就是在瀏覽器上顯示亂碼的原因。

Unicode

從以上幾種編碼規範可以看出,各種編碼規範互不兼容,且只能表示自己需要的字符,於是,國際標準化組織(ISO)決定製定一套全世界通用的編碼規範,這就是Unicode
Unicode包含了全世界所有的字符。Unicode最多可以保存4個字節容量的字符。也就是說,要區分每個字符,每個字符的地址需要4個字節。這是十分浪費存儲空間的,於是,程序員就設計了幾種字符編碼方式,比如:UTF-8,UTF-16,UTF-32。
最廣爲程序員使用的就是UTF-8,UTF-8是一種變長字符編碼,注意:UTF-8不是編碼規範,而是編碼方式。我爲大家介紹一下UTF-8的編碼規則。

編碼規則表

Unicode 十六進制碼點範圍 UTF-8 二進制
0000 0000-0000 007F 0xxxxxxx
0000 0080-0000 07FF 110xxxxx 10xxxxxx
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

如上表所示,對於只需要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進行解碼,也無法顯示出正確的中文字符。

以上,大家就能明白了,亂碼就是編碼和解碼使用的編碼方式不一致,或者編碼時其字庫表中不包含相應字符所導致的結果。

五、使用場景

在計算機內存中,統一使用Unicode編碼,當需要保存到硬盤或者需要傳輸的時候,就轉換爲UTF-8編碼。

文件讀取

從文件中讀取 UTF-8 字符被轉換成Unicode字符到內存中,編輯完成後,保存的時候再把Unicode轉換成UTF-8編碼。
從記事本中讀取

網頁傳輸

瀏覽網頁的時候,服務器會把動態生成的Unicode內容轉換爲UTF-8格式再傳輸到瀏覽器上。
網絡傳輸

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章