1. 程式人生 > >ASCII,Unicode,GBK和UTF-8字符編碼的區別和聯系

ASCII,Unicode,GBK和UTF-8字符編碼的區別和聯系

online 擴展 集合 發展 核心 長度 打開 選擇 最大

如果經常寫python2,肯定會遇到各種“奇怪”的字符編碼問題,每次都通過谷歌解決了,但是為什麽會造成這種亂碼、decode/encode失敗等等,本文就字符和字符編碼做一個總結,更加清晰區分諸多的編碼。

字符集

一個系統支持的所有抽象字符的集合。字符是文字和符號的總稱,包含各個國家文字、標點符號、圖像符號、數字等。它為每一個字符分配一個唯一的ID,一般稱之為碼位、碼點。

字符編碼

它是一套規則,使用該規則能夠將自然語言的字符的一個集合與其他東西的一個集合進行配對,在符號集合和數字系統中建立映射聯系。在計算機中,處理信息是利用元件不同狀態組合來存儲和處理信息的,因此,字符編碼就是將符號轉化為計算機可以接受的數字系統的數,稱為數字代碼。它將上面字符集的碼位轉化為字節序列的規則,此過程稱之為編碼、解碼。

常見字符集

ASCII字符集,GB2312字符集、Unicode字符集等。計算機需要準確處理各種字符集文字,需要進行字符編碼,以便能夠識別和存儲各種文字。

常見字符編碼

UTF編碼

ASCII碼

在計算機內部,所有信息最終都是一個二進制值。每一個二進制位(bit),有0和1兩種狀態,因此,8個二進制位可以組合出256種狀態,這被稱為字節(byte)。上個世紀60年代,美國制定了一套字符編碼,對英文字符與二進制之間做了聯系,這被稱為ASCII碼,一直沿用至今。

ASCII碼一共規定了128個字符,比如SPACE是32,A是65,這128個符號只咱用了一個字節的後面七位,最前面的一位統一規定為0。

非ASCII碼

英語用128個符號編碼足夠了,但是用來表示其他語言顯然是不夠的,於是,歐洲有些國家利用字節中閑置的最高位編入了新的符號,這樣一來,歐洲國家使用的編碼體系,可以最多表示256個字符。

但是到了亞洲國家,使用的符號更多了,光漢字就10萬多個,一個字節只能表示256種符號,肯定是不夠的,就必須使用多個字節表達一個符號。比如常見的GB2312編碼,使用兩個字節表示一個漢字,所以理論上最多可以表示256*256=65536個符號。

GBK碼

GBK編碼是對GB2312的擴展,完全兼容GB2312。采用雙字節編碼方案,剔出xx7F碼位,共23940個碼位,共收錄漢字和圖形符號21886個,GBK編碼方案於1995年12月15日發布。它幾乎完美支持漢字,因此經常會遇見GBK與Unicode的轉換。

Unicode碼

如上文所述,世界上有多種編碼方法,同一個二進制數字可以被解釋稱不同的符號。因此,在打開一個文本文件時候,就必須知道它的編碼方式,用錯誤的編碼方式打開,就會出現亂碼。

假如,有一種編碼,將世界上所有的符號都納入其中,每一種符號都給予獨一無二的編碼,那麽亂碼問題就不會存在了。因此,產生了Unicode編碼,這是一種所有符號的編碼。

Unicode顯然是一個巨大的集合,現在的規模可以容納100多萬個符號。每個符號的編碼都不一樣,比如U+0041表示英語的大寫字母A,U+4e25表示漢字嚴。

在Unicode龐大的字符集的優勢下,還存在一個問題,比如一個漢字,“嚴”的Unicode是十六進制4e25,轉成二進制足足有15位,也就是,這個符號需要2個字節,表示其他字符還存在3個字節或者更多。計算機怎麽區別三個字節表示的是同一個符號而不是分開表示三個呢?如果Unicode統一規定,每個符號用3個字節表示,但是某些字母顯然不需要3個,那麽就浪費了空間,文本文件大小超出了很多,這顯然是不合理的。直到UTF8字符編碼出現了。

UTF8字符編碼

隨著互聯網的發展,強烈要求出現一種統一的編碼方式。UTF8就是在互聯網中使用最多的對Unicode的實現方式。還有其他實現,比如UTF16(字符用2個字節或者4個字節表示),UTF32(字符用4個字節表示)。UTF8是Unicode的實現方式之一,也是最為常見的實現方式。

UTF8的最大特點是,它是一種變長編碼,可以使用1-4個字節表示一個符號,根據不同的符號來變化字節長度。

UTF8編碼規則只有兩條:

1)對於單字節的符號,字節的第一位設為0,後面的7位為這個符號的Unicode碼。因此,對於英文字母,UTF8編碼和ASCII編碼是相同的。

2)對於非單字節(假設字節長度為N)的符號,第一個字節的前N位都設為1,第N+1設為0,後面字節的前兩位一律設為10,剩下的沒有提及的二進制,全部為這個符號的Unicode碼。

下面總結下編碼規則:

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

舉個例子,以漢字“嚴”為例,它的Unicode是4e25(100111000100101),對應上表,處於第三行,因此嚴的UTF8編碼需要3個字節。然後,從嚴的最後一個二進制位開始,從後向前填入X,多出的位補0,就可以計算出 11100100 10111000 10100101,轉成十六進制就是E4B8A5。

Unicode與UTF8之間轉換

嚴的Unicode編碼是4e25,UTF8是E4B8A5,兩者是不一樣的,可以通過程序實現轉碼。

在Windows下有記事本小程序notepad.exe,打開文件後可以通過另存為,選擇編碼格式,重新保存新的文本文件。支持ANSI,Unicode,Unicde big endlian和UTF8。

1)ANSI是記事本默認編碼方式,對於簡體中文是GB2312。正是因為這個,Python讀取文本文件時候一定要小心它的編碼類型,因為不能直觀到文本文件的格式。

2)Unicode編碼這裏使用UCS-2編碼方式,采用兩個字節存入字符的Unicode編碼。

Python編碼為什麽如此蛋疼

總結了幾種編碼和編碼規則,但是在Python2中編碼問題就像幽靈一樣困擾著開發者,其根本解決辦法是理解清楚python2在內存中的字符存在的編碼格式,在程序代碼中始終采用Unicode編碼處理,只有在輸出時候才做encode處理。核心思想是:保證Python運行過程中字符編碼格式是unicode編碼,在任何地方。關於Python亂碼問題,會在專門文章做分析,這裏提供一個鏈接供參考。

Python編碼為什麽那麽蛋疼?

編碼探測

使用 chardet 可以很方便的實現字符串/文件的編碼檢測。尤其是中文網頁,有的頁面使用GBK/GB2312,有的使用UTF8,使用chardet基本可以探測出編碼格式。

延伸閱讀

談談Unicode編碼

ASCII,Unicode,GBK和UTF-8字符編碼的區別和聯系