天天看點

字元集和編碼字元集和編碼--石鍋拌飯

 今天被一個python編碼問題折騰了半下午。編碼問題一直是個讓人比較糾結的問題,寫這篇文章想簡單的總結下python中一些常見的編碼問題以及解決方式。這是第一篇,先總結下字元集和編碼的一些基本概念和内容。

字元集(Character Set):顧名思義,就是字元的集合。如ASCII字元集,定義了128個字元,而gb2312定義了7445個字元。

計算機中字元集的嚴格定義來說指的是已編号的字元的有序集合(不一定連續)。

字元碼(Code Point):指的就是字元集中每一個字元的數字編号。比如ASCII字元集用0-127這連續的128個數字分别表示128個字元。GBK字元集使用區位碼的方式為每一個字元編号,首先定義一個94X94的矩陣,行稱為“區”,列稱為“位”。然後将全部國标漢字放入矩陣其中,這樣每一個漢字就能夠用唯一的“區位”碼來辨別了。比如“中”字被放到54區第48位。是以字元碼就是5448。

而Unicode中将字元集依照一定的類别劃分到0~16這17個層面(Planes)中。每一個層面中擁有216=65536個字元碼,是以Unicode總共擁有的字元碼,也即是Unicode的字元空間總共同擁有17*65536=1114112。

字元編碼:将字元集中的字元碼映射為位元組流的一種詳細實作方案。比如ASCII字元編碼規定使用單位元組中低位的7個比特去編碼全部的字元。

比如‘A’的編号是65,用單位元組表示就是0×41。是以寫入儲存設備的時候就是b’01000001’。

GBK編碼則是将區位碼(GBK的字元碼)中的區碼和位碼的分别加上0xA0(160)的偏移(之是以要加上這種偏移,主要是為了和ASCII碼相容)。比如剛剛提到的“中”字,區位碼是5448。十六進制是0×3630,區碼和位碼分别加上0xA0的偏移之後就得到0xD6D0,這就是“中”字的GBK編碼結果。

代碼頁(Code Page)一種字元編碼詳細形式。

早期字元相對少,是以一般會使用類似表格的形式将字元直接映射為位元組流,然後通過查表的方式來實作字元的編解碼。現代作業系統沿用了這樣的方式。

比如Windows使用936代碼頁、Mac系統使用EUC-CN代碼頁實作GBK字元集的編碼,名字盡管不一樣。但對于同一漢字的編碼肯定是一樣的。

當中ASCII标準本身就規定了字元和字元編碼方式,採用單位元組編碼,總共能夠編碼128個字元,如空格的編碼是32。小寫字母a是97,是以ASCII既是字元集又是編碼方案。

對于英文來說,128個符号編碼已經夠用了,然而對于其它語言比方中文,顯然就不夠了。

是以就出現了多位元組字元集MBCS(Multi-Byte Character Set)。如GB2312,GBK,GB18030,BIG5等編碼都屬于MBCS。

由于MBCS大都使用2個位元組編碼,是以有時候也叫DBCS(Double-Byte Character Set)。

我們在Linux系統中看到含有中文的檔案編碼經常是CP936,那這個事實上就是GBK編碼了,這個名字的由來是由于IBM以前發明了一個Code Page的概念,把這些多位元組編碼收入當中,GBK編碼正好位于936頁,是以就簡稱CP936了。

而後大家認為各種編碼太多不友善,不如全部語言字元都使用一套字元集來表示。于是就出現了Unicode。

Unicode/UCS(Unicode Character Set)标準僅僅是一個字元集标準,可是它并沒有規定字元的存儲和傳輸方式。

Unicode是一種字元集而不是詳細的編碼,它主要有3種編碼方式:最初Unicode标準使用2個位元組表示一個字元。編碼方案是UTF-16,還有使用4個位元組表示一個字元的編碼方案UTF-32。而後來使用英文字元的國家認為不好,原來一個字元存儲的如今變成了2個字元。空間增大了一倍,由此UTF-8編碼。UTF-8編碼中。英文占一個位元組,中文占3個位元組。

如上面所提到的,Unicode字元集主要採用UTF-8,UTF-16等方式進行編碼存儲。當然,gbk等字元編碼也能夠編碼Unicode全部的字元集,也算是Unicode的一種字元編碼。那麼這種話。計算機怎樣知道檔案採用哪種方式編碼呢?Unicode規範中又定義,在每一個檔案最前面增加一個表示編碼順序的字元BOM(Byte Order Mark)。比方石鍋拌飯中的“石”的UTF-16編碼是77F3,採用UTF-16方式存儲使用2個位元組,一個位元組是77,一個位元組是F3.存儲的時候假設77在前面,F3在後面。則稱為big endian方式。反之,則是Little endian方式。。這個字元正好也是2個位元組。為FEFF。假設一個文本檔案頭兩個位元組威FEFF,則表示採用Big endian方式編碼;否則就是Little endian方式。

而UTF-8的BOM是EFBBBF,總結例如以下:

并非全部的編輯器都會寫入BOM。但即使沒有BOM,Unicode還是能夠讀取的,僅僅是須要指定編碼,不然可能會失效。

此外另一種不得不提的是ANSI,ANSI在windows系統中極為常見,事實上ANSI是Windows code pages,這個模式依據目前的locale標明詳細編碼,假設系統locale是中文簡體則採用GBK編碼,繁體中文為BIG5編碼,日文則是JIS編碼。

此外windows中喜歡把BOM_UTF16_LE編碼稱作Unicode,把BOM_UTF8稱作UTF-8。也有人說UTF-8不須要BOM來标示,事實上是不多的。這是由于編輯器一般預設使用UTF-8來測試字元編碼而已,假設能夠成功解碼。就用UTF-8進行解碼。即便最開始採用的是ANSI儲存的,打開檔案時還是最先使用UTF-8來解碼。比方你用windows的記事本程式建立一個檔案,寫入“姹塧”并用ANSI編碼儲存。再次打開檔案,會發現“姹塧”會變成“漢a”。

還是以石鍋拌飯的“石”字來看看在windows以下各種編碼方式下的編碼吧。

打開windows的記事本程式,分别用ANSI。Unicode(實際是BOM_UTF16_LE),Unicode Big endian。UTF-8這幾種編碼方式看看終于是否跟之前分析的一樣。

這裡使用UltraEdit來檢視16進制編碼,能夠打開“編輯”-》16進制編輯功能來檢視。

ANSI編碼儲存,編碼是CA AF。這也表示GBK編碼存儲也採用了Big endian方式。

Unicode編碼儲存,編碼是FF FE F3 77。 

Unicode Big endian編碼儲存,編碼是 FE FF 77 F3。 

UTF-8編碼儲存。編碼是EF BB BF E7 9F B3。

<a target="_blank" href="http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html">Python字元編碼具體解釋</a>

<a target="_blank" href="http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html">阮一峰: 字元編碼筆記</a>

<a target="_blank" href="http://www.zhihu.com/question/20650946">知乎: Windows 記事本的 ANSI、Unicode、UTF-8 這三種編碼模式有什麼差别?</a>

<a target="_blank" href="http://blog.jobbole.com/74109/">關于字元編碼。你所須要知道的</a>

本文轉自mfrbuaa部落格園部落格,原文連結:http://www.cnblogs.com/mfrbuaa/p/5386332.html,如需轉載請自行聯系原作者