一、python常見字元編碼
字元編碼的常用種類介紹
第一種:ascii碼
ascii(american standard code for information interchange,美國資訊交換标準代碼)是基于拉丁字母的一套電腦編碼系統,主要用于顯示現代英語和其他西歐語言。它是現今最通用的單位元組編碼系統,并等同于國際标準iso/iec 646。如下圖所示:
由于計算機是美國人發明的,是以,最早隻有127個字母被編碼到計算機裡,也就是大小寫英文字母、數字和一些符号,這個編碼表被稱為ascii編碼,比如大寫字母 a的編碼是65,小寫字母 a的編碼是97。後128個稱為擴充ascii碼。
在這裡,每一位0或者1所占的空間機關為bit(比特),這是計算機中最小的表示機關,每8個bit組成一個字元,這是計算機中最小的存儲機關。
常見換算機關:
bit 位,計算機中最小的表示機關
8bit = 1bytes 位元組,最小的存儲機關,1bytes縮寫為1b
1kb=1024b
1mb=1024kb
1gb=1024mb
1tb=1024gb
第二種:gbk 和 gb2312
對于我們來說能在計算機中顯示中文字元是至關重要的,然而ascii表裡連一個偏旁部首也沒有。是以我們還需要一張關于中文和數字對應的關系表。一個位元組隻能最多表示256個字元,要進行中文顯然一個位元組是不夠的,是以我們需要采用兩個位元組來表示,而且還不能和ascii編碼沖突,是以,中國制定了gb2312編碼,用來把中文編進去。
第三種:unicode
但如以來,就會出現一個問題,各個國家都一套自己的編碼,就不可避免會有沖突,這是該怎麼辦呢?
是以,unicode應運而生。unicode把所有語言都統一到一套編碼裡,這樣就不會再有亂碼問題了。
unicode标準也在不斷發展,但最常用的是用兩個位元組表示一個字元(如果要用到非常偏僻的字元,就需要4個位元組)。現代作業系統和大多數程式設計語言都直接支援unicode。
現在,分析一下ascii編碼和unicode編碼的差別:
ascii編碼是1個位元組,而unicode編碼通常是2個位元組。
字母a用ascii編碼是十進制的65,二進制的01000001;
字元0用ascii編碼是十進制的48,二進制的00110000;
漢字“中”已經超出了ascii編碼的範圍,用unicode編碼是十進制的20013,二進制的01001110 00101101。
如果把ascii編碼的a用unicode編碼,隻需要在前面補0就可以,是以,a的unicode編碼是00000000 01000001。
但如果統一成unicode編碼,亂碼問題從此消失了。但是,如果你寫的文本基本上全部是英文的話,用unicode編碼比ascii編碼需要多一倍的存儲空間,在存儲和傳輸上就十分不劃算。
第四種:utf-8
基于節約的原則,出現了把unicode編碼轉化為“可變長編碼”的utf-8編碼。utf-8編碼把一個unicode字元根據不同的數字大小編碼成1-6個位元組,常用的英文字母被編碼成1個位元組,漢字通常是3個位元組,隻有很生僻的字元才會被編碼成4-6個位元組。如果你要傳輸的文本包含大量英文字元,用utf-8編碼就能節省空間了。如下所示:
從上面的表格還可以發現,utf-8編碼有一個額外的好處,就是ascii編碼實際上可以被看成是utf-8編碼的一部分,是以,大量隻支援ascii編碼的曆史遺留軟體可以在utf-8編碼下繼續工作。
我們總結一下現在計算機系統通用的字元編碼工作方式:
在計算機記憶體中,統一使用unicode編碼,當需要儲存到硬碟或者需要傳輸的時候,就轉換為utf-8編碼。
用記事本編輯的時候,從檔案讀取的utf-8字元被轉換為unicode字元到記憶體裡,編輯完成後,儲存的時候再把unicode轉換為utf-8儲存到檔案。如下圖:
二、python常見字元編碼間的轉換
(一)unicode和utf-8
unicode 起到了2個作用:
直接支援全球所有語言,每個國家都可以不用再使用自己之前的舊編碼了,用unicode就可以了。(就跟英語是全球統一語言一樣)
unicode包含了跟全球所有國家編碼的映射關系。
unicode解決了字元和二進制的對應關系,但是使用unicode表示一個字元,太浪費空間。例如:利用unicode表示“python”需要12個位元組才能表示,比原來ascii表示增加了1倍。由于計算機的記憶體比較大,并且字元串在内容中表示時也不會特别大,是以内容可以使用unicode來處理,但是存儲和網絡傳輸時一般資料都會非常多,那麼增加1倍将是無法容忍的。
為了解決存儲和網絡傳輸的問題,出現了unicode transformation format,學術名utf,即:對unicode中的進行轉換,以便于在存儲和網絡傳輸時可以節省空間。
utf-8: 使用1、2、3、4個位元組表示所有字元;優先使用1個字元、無法滿足則使增加一個位元組,最多4個位元組。英文占1個位元組、歐洲語系占2個、東亞占3個,其它及特殊字元占4個。
utf-16: 使用2、4個位元組表示所有字元;優先使用2個位元組,否則使用4個位元組表示。
utf-32: 使用4個位元組表示所有字元。
總結:utf 是為unicode編碼 設計 的一種 在存儲 和傳輸時節省空間的編碼方案。
(二)字元在硬碟上的存儲
首先要明确的一點就是,無論以什麼編碼在記憶體裡顯示字元,存到硬碟上都是2進制。
比如:
ascii編碼(美國):
l 0b1101100
o 0b1101111
v 0b1110110
e 0b1100101
gbk編碼(中國):
老 0b11000000 0b11001111
男 0b11000100 0b11010000
孩 0b10111010 0b10100010
還要注意的一點是,存到硬碟上時是以何種編碼存的,再從硬碟上讀出來時,就必須以何種編碼讀(開頭聲明或轉換),要不然就亂了。
(三)編碼的轉換
雖然有了unicode and utf-8 ,但是由于曆史問題,各個國家依然在大量使用自己的編碼,比如中國的windows,預設編碼依然是gbk,而不是utf-8。基于此,如果中國的軟體出口到美國,在美國人的電腦上就會顯示亂碼,因為他們沒有gbk編碼。是以該怎麼辦呢?還記得我們講unicode其中一個功能是其包含了跟全球所有國家編碼的映射關系,這時就派上用場了。無論你以什麼編碼存儲的資料,隻要你的軟體在把資料從硬碟讀到記憶體裡,轉成unicode來顯示,就可以了。由于所有的系統、程式設計語言都預設支援unicode,那你的gbk軟體放到美國電腦上,加載到記憶體裡,變成了unicode,中文就可以正常展示啦。
python3執行過程
解釋器找到代碼檔案,把代碼字元串按檔案頭定義的編碼加載到記憶體,轉成unicode,把代碼字元串按照文法規則進行解釋,所有的變量字元都會以unicode編碼聲明。在py3上 把你的代碼以utf-8編寫, 儲存,然後在windows上執行,發現可以正常執行。其實utf-8編碼之是以能在windows gbk的終端下顯示正常,是因為到了記憶體裡python解釋器把utf-8轉成了unicode , 但是這隻是python3, 并不是所有的程式設計語言在記憶體裡預設編碼都是unicode,比如 萬惡的python2 就不是, 是ascii,想寫中文,就必須聲明檔案頭的coding為gbk or utf-8, 聲明之後,python2解釋器僅以檔案頭聲明的編碼去解釋你的代碼,加載到記憶體後,并不會主動幫你轉為unicode,也就是說,你的檔案編碼是utf-8,加載到記憶體裡,你的變量字元串就也是utf-8, 這意味着什麼?意味着,你以utf-8編碼的檔案,在windows是亂碼。
其實亂是正常的,不亂才不正常,因為隻有2種情況 ,你的windows上顯示才不會亂。
python2并不會自動的把檔案編碼轉為unicode存在記憶體裡。
字元串以gbk格式顯示
字元串是unicode編碼
是以我們隻有手動轉,python3 自動把檔案編碼轉為unicode必定是調用了什麼方法,這個方法就是,decode(解碼) 和encode(編碼)。
方法如下:
utf-8 --> decode 解碼 --> unicode
unicode --> encode 編碼 --> gbk / utf-8
規則如下:
(四)python bytes 類型
把8個二進制一組稱為一個byte,用16進制來表示。為的就是讓人們看起來更可讀。我們稱之為bytes類型,即位元組類型。
python2的字元串其實更應該稱為位元組串。 通過存儲方式就能看出來, 但python2裡還有一個類型是bytes,難道又叫bytes又叫字元串?是的,在python2裡,bytes == str , 其實就是一回事。除此之外, python2裡還有個單獨的類型是unicode , 把字元串解碼後,就會變成unicode。
python2的預設編碼是ascii碼,當後來大家對支援漢字、日文、法語等語言的呼聲越來越高時,python于是準備引入unicode,但若直接把預設編碼改成unicode的話是不現實的, 因為很多軟體就是基于之前的預設編碼ascii開發的,編碼一換,那些軟體的編碼就都亂了。是以python 2就直接用了一個新的字元類型,就叫unicode類型,比如你想讓你的中文在全球所有電腦上正常顯示,在記憶體裡就得把字元串存成unicode類型。
python3 除了把字元串的編碼改成了unicode, 還把str 和bytes 做了明确區分, str 就是unicode格式的字元, bytes就是單純二進制啦。
在py3裡看字元,必須得是unicode編碼,其它編碼一律按bytes格式展示。
python隻要出現各種編碼問題,無非是哪裡的編碼設定出錯了。
常見編碼錯誤的原因有以下這些:
python解釋器的預設編碼
python源檔案檔案編碼
terminal使用的編碼
作業系統的語言設定
最後總結一下:
python3 檔案預設編碼是utf-8 , 字元串編碼是 unicode
以utf-8 或者 gbk等編碼的代碼,加載到記憶體,會自動轉為unicode正常顯示。
python2 檔案預設編碼是ascii , 字元串編碼也是 ascii , 如果檔案頭聲明了是gbk,那字元串編碼就是gbk。
以utf-8 或者 gbk等編碼的代碼,加載到記憶體,并不會轉為unicode,編碼仍然是utf-8或者gbk等編碼。