1. 程式人生 > >字元編碼ASCII、GB2312、Unicode、UTF-8——深入解析

字元編碼ASCII、GB2312、Unicode、UTF-8——深入解析

幾個值得深思的問題

  1. 什麼是字元?

    字元是各種文字和符號的總稱,包括各個國家文字、標點符號、圖形符號、數字等。

  2. 什麼是字符集?

    字符集是多個字元的集合,字符集種類較多,每個字符集包含的字元個數不同,常見字符集有:ASCII字符集、ISO 8859字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等

  3. 什麼是字元編碼?

    1、 計算機要準確的處理各種字符集文字,需要進行字元編碼,以便計算機能夠識別和儲存各種文字。 
    2、 字元編碼(encoding)和字符集不同。字符集只是字元的集合,不一定適合作網路傳送、處理,有時須經編碼(encode)後才能應用。如Unicode可依不同需要以UTF-8、UTF-16、UTF-32等方式編碼。 
    3、字元編碼就是以二進位制的數字來對應字符集的字元。 因此,對字元進行編碼,是資訊交流的技術基礎。

  4. 概括

    1、使用哪些字元。也就是說哪些漢字,字母和符號會被收入標準中。所包含“字元”的集合就叫做“字符集”。 
    2、規定每個“字元”分別用一個位元組還是多個位元組儲存,用哪些位元組來儲存,這個規定就叫做“編碼”。 
    3、各個國家和地區在制定編碼標準的時候,“字元的集合”和“編碼”一般都是同時制定的。因此,平常我們所說的“字符集”,比如:GB2312, GBK, JIS 等,除了有“字元的集合”這層含義外,同時也包含了“編碼”的含義。 
    4、注意:Unicode字符集有多種編碼方式,如UTF-8、UTF-16等;ASCII只有一種;大多數MBCS(包括GB2312,GBK)也只有一種。

  5. 有趣的例子

    1、在顯示器上看見的文字、圖片等資訊在電腦裡面,其實並不是我們看見的樣子,即使你知道所有資訊都儲存在硬盤裡,把它拆開也看不見裡面有任何東西,只有些碟片。假設,你用顯微鏡把碟片放大,會看見碟片表面凹凸不平,凸起的地方被磁化,凹的地方是沒有被磁化;凸起的地方代表數字1,凹的地方代表數字0。硬碟只能用0和1來表示所有文字、圖片等資訊。 
    2、那麼字母”A”在硬碟上是如何儲存的呢?可能小張計算機儲存字母”A”是1100001,而小王儲存字母”A”是11000010,這樣雙方交換資訊時就會誤解。比如小張把1100001傳送給小王,小王並不認為1100001是字母”A”,可能認為這是字母”X”,於是小王在用記事本訪問儲存在硬碟上的1100001時,在螢幕上顯示的就是字母”X”。也就是說,小張和小王使用了不同的編碼表。小張用的編碼表是ASCII,ASCII編碼表把26個字母都一一的對應到2進位制1和0上;小王用的編碼表可能是EBCDIC,只不過EBCDIC編碼與ASCII編碼中的字母和01的對應關係不同。一般地說,開放的作業系統(LINUX 、WINDOWS等)採用ASCII 編碼,而大型主機系統(MVS 、OS/390等)採用EBCDIC 編碼。在傳送資料給對方前,需要事先告知對方自己所使用的編碼,或者通過轉碼,使不同編碼方案的兩個系統可溝通自如。

  6. 這個例子說明了三點

    1、不管是任何文字圖片等,最後都會以二進位制的形式儲存到電腦的磁碟中(比如記事本A.txt,內容為”ABC”檔案,在此磁碟中表現的就是01 01這種二進位制形式) 
    碟片表面凹凸不平,凸起的地方被磁化,凹的地方是沒有被磁化,凸起的地方代表數字1,凹的地方代表數字0。硬碟只能用0和1來表示所有文字、圖片等資訊。是的 很強勢 
    2、 任何檔案要儲存到電腦中,都會事先進行編碼,然後儲存到電腦的磁碟中,比如A.txt檔案,預設編碼為ANSI編碼,也可以編碼為UTF-8,然而不同的編碼方式 對應著計算機用一個位元組還是多個位元組儲存,用哪些位元組來儲存。 
    3、在雙方資料進行通訊時,要麼就保證傳送方和接受方的資料編碼是相同,要麼就是其中一方需要轉碼

  7. 什麼是位元組和位?

    位元組byte和位bit是電腦裡的資料量單位。 
    1.按計算機中的規定,一個英文的字元佔用一個位元組,而一個漢字以及漢字的標點符號、字元都佔用兩個位元組。 
    2.1個位元組等於8位 1byte=8bit 
    3.1bit在磁碟中以二進位制01的形式儲存 凸起的地方代表數字1,凹的地方代表數字0

字元編碼種類

ASCII

ASCII碼是西歐編碼的方式,採取7位編碼,所以是2^7=128,共可以表示128個字元,包括34個字元,(如換行LF,回車CR等),其餘94位為英文字母和標點符號及運算子號等。 
ASCII表

重點:

字符集:從符號(NUL=”/0”=“空操作字元”)到“Z”再到“DEL”符號 
字元編碼範圍:二進位制:00000000——01111111 十進位制:0-127 
佔用位元組:1位元組 8bit 碟片儲存方式:凹凹凹凹凹凹凹凹——凸凸凸凸凸凸凸凸

注:NUL:‘\0’是一個ASCII碼為0的字元,從ASCII碼錶中可以看到ASCII碼為0的字元是“空操作字元”,它不引起任何控制動作,也不是一個可顯示的字元。

但我們發現ASCII碼是沒有中文編碼的,顯然在天朝是不夠用的,於是GB2312誕生了。

GB2321

GB2312 是對 ASCII 的中文擴充套件。相容ASCII。

編碼規定: 
編碼小於127的字元與ASCII編碼相同, 
特性:兩個大於127的字元連在一起時,就表示一個漢字,前面的一個位元組(稱之為高位元組)從0xA1用到0xF7,後面一個位元組(低位元組)從0xA1到0xFE,這樣我們就可以組合出大約7000多個簡體漢字了。

字符集:從符號(NUL=”/0”=“空操作字元”)到“Z”到“齇”(簡體中文) 
字元編碼範圍:16進位制:0x0000-(中間有一部分是未使用的)-0xF7FE 
佔用位元組:英文 1位元組 8bit 碟片儲存方式:凹凹凹凹凹凹凹凹——凸凸凸凸凸凸凸凸 
中文 2位元組 16bit 凹凹凹凹凹凹凹凹凹凹凹凹凹凹凹凹——…

GBK

GBK 相容ASCLL 相容 GB2312 是GB2312的擴充套件 
但是中國的漢字太多了,我們很快就就發現有許多人的人名沒有辦法在這裡打出來,不得不繼續把 GB2312 沒有用到的碼位找出來用上。後來還是不夠用,於是乾脆不再要求低位元組一定是127號之後的內碼,只要第一個位元組是大於127就固定表示這是一個漢字的開始,不管後面跟的是不是擴充套件字符集裡的內容。結果擴充套件之後的編碼方案被稱為 “GBK” 標準,GBK 包括了 GB2312 的所有內容,同時又增加了近20000個新的漢字(包括繁體字)和符號。

Unicode

Unicode是國際組織制定的可以容納世界上所有文字和符號的字元編碼方案。 
目前的Unicode字元分為17組編排,0x0000至0x10FFFF,每組稱為平面(Plane),而每平面擁有65536個碼位,共1114112個。然而目前只用了少數平面。UTF-8、UTF-16、UTF-32都是將數字轉換到程式資料的編碼方案。

UTF-8

UTF-8以位元組為單位對Unicode進行編碼。從Unicode到UTF-8的編碼方式如下: 
UTF-8的特點是對不同範圍的字元使用不同長度的編碼。對於0x00-0x7F之間的字元,UTF-8編碼與ASCII編碼完全相同。UTF-8編碼的最大長度是6個位元組。從上表可以看出,6位元組模板有31個x,即可以容納31位二進位制數字。Unicode的最大碼位0x7FFFFFFF也只有31位。 
例1:“漢”字的Unicode編碼是0x6C49。0x6C49在0x0800-0xFFFF之間,使用用3位元組模板了:1110xxxx 10xxxxxx 10xxxxxx。將0x6C49寫成二進位制是:0110 1100 0100 1001, 用這個位元流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。 
舉一個例子:It’s 知乎日報

你看到的unicode字符集是這樣的編碼表:

I 0049 
t 0074 
’ 0027 
s 0073 
0020 
知 77e5 
乎 4e4e 
日 65e5 
報 62a5 
每一個字元對應一個十六進位制數字。

計算機只懂二進位制,因此,嚴格按照unicode的方式(UCS-2),應該這樣儲存:

I 00000000 01001001 
t 00000000 01110100 
’ 00000000 00100111 
s 00000000 01110011 
00000000 00100000 
知 01110111 11100101 
乎 01001110 01001110 
日 01100101 11100101 
報 01100010 10100101 
這個字串總共佔用了18個位元組,但是對比中英文的二進位制碼,可以發現,英文前9位都是0!浪費啊,浪費硬碟,浪費流量。

怎麼辦?

UTF

UTF-8是這樣做的:

  1. 單位元組的字元,位元組的第一位設為0,對於英語文字,UTF-8碼只佔用一個位元組,和ASCII碼完全相同;
  2. n個位元組的字元(n>1),第一位元組的前n位設為1,第n+1位設為0,後面位元組的前兩位都設為10,這n個位元組的其餘空位填充該字元unicode碼,高位用0補足。

這樣就形成了如下的UTF-8標記位:

高位位元組低位位元組低位位元組低位位元組低位位元組低位位元組
0xxxxxxx
110xxxxx10xxxxxx
1110xxxx10xxxxxx10xxxxxx
11110xxx10xxxxxx10xxxxxx10xxxxxx
111110xx10xxxxxx10xxxxxx10xxxxxx10xxxxxx
1111110x10xxxxxx10xxxxxx10xxxxxx10xxxxxx10xxxxxx
… ….

比如”知”字 在Unicode中佔用兩個位元組,那麼第一位元組(我叫它高位位元組)的前兩位設位1,第三位設為10,後面低位位元組設為前兩位設為10, “知”→ 11100111 10011111 10100101 
怎麼知道“知”字佔用兩個位元組的?首先要知道Unicode字符集中,“知”字的編碼為77e5,然後轉化為二進位制流01110111 11100101的bit,每8bit等於1byte 所以就佔兩個位元組 
於是,”It’s 知乎日報“就變成了: 
I 01001001 
t 01110100 
’ 00100111 
s 01110011 
00100000 
知 11100111 10011111 10100101 
乎 11100100 10111001 10001110 
日 11100110 10010111 10100101 
報 11100110 10001010 10100101 
和上邊的方案對比一下,英文短了,每個中文字元卻多用了一個位元組。但是整個字串只用了17個位元組,比上邊的18個短了一點點。 
劇透:一切都是為了節省你的硬碟和流量。

一圖解憂愁

漢子對照表

1.從這個可以看出,同樣的字符集,但unicode編碼和gbk編碼是不同的,所以unicode字符集不相容gbk字符集。
2.只要知道unicode字符集的編碼表,就可以用UTF8編碼規則找到UTF-8對應的漢字編碼。