編碼(python版) 最近在學習python的過程中,被不同的編碼搞得有點暈,於是看了前人的留下的文檔,加上自己的理解,準備寫下來,分享給正在為編碼苦苦了掙扎的你。 編碼的概念 編碼就是將信息從一種格式轉換成另一種格式,電腦只認識二進位,簡單的理解,將我們眼睛看到的文字轉換為電腦能夠識別的二進 ...
編碼(python版)
最近在學習python的過程中,被不同的編碼搞得有點暈,於是看了前人的留下的文檔,加上自己的理解,準備寫下來,分享給正在為編碼苦苦了掙扎的你。
編碼的概念
編碼就是將信息從一種格式轉換成另一種格式,電腦只認識二進位,簡單的理解,將我們眼睛看到的文字轉換為電腦能夠識別的二進位格式視為編碼,而二進位以某種編碼格式轉換為我們能看的文字的過程可以看成是解碼。既然電腦只能認識二進位0,1,那麼我們用的字母、數字和文字等是怎樣和他們對應的呢?那就請繼續看吧!
python中查看預設的編碼規範是:
import sys print(sys.getdefaultencoding()) #運行結果: utf-8
ASCⅡ碼
我們都知道電腦是米國發明的,起初的時候也只有米國那些國家使用,而他們的語言僅僅只有26個字母組成,再加上一些符號,所以在一開始的時候,用的編碼規則就是ASCⅡ碼。ASCⅡ,中文名叫美國信息交換標準代碼,因為名叫American Standard Code for Information Interchange,下麵我們來看看ASCⅡ表:
ASCⅡ碼用一個位元組,也就是8位二進位組來標識一個字元,比如00100001就代表字元!,第一版的ASCⅡ沒有用到最高的一個bit,所以取值範圍為0-127,只能表示128字元。為了滿足西歐等國家的字元要求,於是用上了最高位的bit,能表示的字元也從128增加到了256個。
在python中使用函數ord(),可以字元轉換為對應數值,使用函數chr可以將數值轉換為對應字元:
>>> ord("a") #將字元轉換為數值 97 >>> ord("A") 65 >>> chr(65) 'A' >>> chr(97) #將數值轉換為字元 'a' >>>
GB2312和GBK
當電腦漂洋過海來到了中國,ASCⅡ已經不能滿足我大天朝的需求了,常用的漢字大致都有2k-3k。所以中國國家標準總局在1980發佈了《信息交換用漢字編碼字元集》,也就是GB2313標準。GB2312一共收錄了7445個字元(6763個漢字和682個其他符號),包括拉丁字母、希臘字母和日文平假名等,基本上滿足了國人的需求。
在GB2312中每個漢字使用兩個位元組來表示,分為高位元組和低位元組,漢字區高位元組從B0-F7,低位元組從A1-FE,占用的碼位是72*94=6768,其中有5個空位是D7FA-D7FE,規定第一個位元組大於127的就代表這是一個漢字的開始(這一個位元組和下一個位元組就代表一個漢字),每個位元組的最高位都位1。
但是對於人名、古漢語等方面出現的罕用字,GB2312不能處理,後來就出現了GBK。GBK向下相容GB2312,其編碼範圍從8140到FEFE(不包括xx7F),共23940個碼位,共收錄了21003個漢字,這還是很厲害的了。現在我們使用的電腦預設的就是GBK編碼。
Unicode和UTF-8
我們國家搞出了GBK,其他的國家也搞出了各種各樣的編碼,比如小日本的SJIJ,寶島臺灣的BIG5,國際組織一看,這不行啊,每個地方都各自搞各自的,那麼在不同的國家之間就會出現不相容,我用GBK編碼格式寫的軟體,弄到你編碼格式為SJIJ的電腦就不能執行了。所以就出現了Unicode,也稱萬國碼。unicode是用2個位元組來表示一個字元的,65536類個字元,這足以覆蓋世界上所有的文字。
這樣雖好,但是美國人民就不開心了,我一個字母,比如'a'就需要占用一個位元組,現在需要占用兩個位元組,這樣就大大的浪費了記憶體和硬碟的空間,所有後來就出現了UTF-32,UTF-16和UTF-8,前兩個這裡就不在敖述了,現在並不常用,我們這看看這個UTF-8,UTF-8是一種可變長的編碼格式,存儲英文字母只需要一個位元組,存儲漢字需要3個位元組,但超大字元集中的更大多數漢字要占4個位元組。我們在記憶體裡面的數據是unicode,在傳輸數據和保存數據的時候使用UTF-8已節省空間和帶寬。
Python2的編碼
在python2中預設的編碼是ASCII,python2的字元串類型有兩種:str和Unicode,這兩個只是字元串類型的名字,我們主要看它們在記憶體裡面的記憶體地址:
#coding=utf8 name = '彬彬' name2 = u'彬彬' #加u,將字元串類型改為Unicode print repr(name) print repr(name2)
#輸出結果
'\xe5\xbd\xac\xe5\xbd\xac' #位元組數據
u'\u5f6c\u5f6c' #Unicode數據
在python2中,str類型字元串類型在記憶體中存儲的是bytes數據,Unicode類型字元串在記憶體中存儲的是unicode數據。那兩種數據之間是什麼關係了?這裡就涉及到瞭解碼(encode)和編碼(decode)了。
#coding=utf8 name = '彬彬' #name為位元組數據類型 name2 = u'彬彬' #name為unicode數據類型 print repr(name) print repr(name2) name3 = name.decode('utf8') print type(name3) print repr(name3) name4 = name2.encode('utf8') print type(name4) print repr(name4) #運行結果
'\xe5\xbd\xac\xe5\xbd\xac' u'\u5f6c\u5f6c' <type 'unicode'> u'\u5f6c\u5f6c' <type 'str'> '\xe5\xbd\xac\xe5\xbd\xac'
由上運行結果可知,unicode轉換為bytes數據的過程是編碼。從bytes數據轉換為unicode數據的過程是解碼。我們再來看一下:
#coding=utf8 name = '彬彬' name3 = name.decode('big5') print name3 #運行結果 敶砍蓮
我們可以看到得到一堆亂文,name存在記憶體里的時候是以UTF編碼成的bytes數據,而我們這裡decode('big5')使用big5來解碼,雖然成功了,但是輸出結果卻不是我們想要的結果。
當我們把第一行coding改為big5的時候就不會出現亂文了,
#coding=big5 name = '彬彬' name3 = name.decode('big5') print name3 #運行結果 彬彬
所以我們用什麼規則編碼的就要用什麼區解碼!
註意:我們在終端顯示出來的明文,就是你用戶所看到的,其實都是已經轉換成unicode到記憶體裡面,而bytes數據一般都是電腦識別的。
Python3的編碼
在Python3中也定義了2種類型的字元串類型,str和bytes,str類型存儲unicode數據,bytes類型存儲bytes數據。
name = "彬彬" name2 = b"hello" print(type(name)) print(type(name.encode('utf8'))) print(type(name.encode('gbk'))) print(type(name2)) print(type(name2.decode('utf8'))) #運行結果 <class 'str'> <class 'bytes'> <class 'bytes'> <class 'bytes'> <class 'str'>
如上運行結果,bytes轉換為unicode為解碼,uicode轉為bytes數據類型為編碼。
由上圖所示,在不同的編碼之間轉換的時候,我們都要經過unicode這個中轉站,沒辦法,雖然unicode老大哥強大呢,當我們想把utf-8編碼的數據轉換為gbk的,我們就需要把utf-8的數據先解碼成unicode,再由unicode編碼成gbk。
在py2和py3中有個重要的區分就是,py2會自動把bytes數據解碼成unicode,而py3就不會自動把bytes解碼成unicode了。所以說py3更清晰的區分了bytes數據和unicode。
#py2中 print(u"liu" + "bin") #運行結果 liubin
#py3中 print("liu" + b"bin") #運行結果 Traceback (most recent call last): File "E:/py/字元編碼2.py", line 2, in <module> print("liu" + b"bin") TypeError: Can't convert 'bytes' object to str implicitly
print("liu" + (b"bin").decode('utf8'))
#運行結果
liubin
一個.py文件的"一生"
那我們創建.py文件,到執行.py文件,這裡面的編碼和解碼是怎麼來的呢?
1.當我們創建一個.py文件的時候,會有一個預設的編碼格式(這裡以pycharm為例),在右下角,預設是UTF-8,當然你也可以選擇其他的編碼:
2.當我們在.py文件裡面寫入代碼的時候,會以unicode的編碼格式保存在記憶體中;
print("你好,世界!")
3.當我們保存的時候,會將Unicode數據編碼成utf-8格式的數據,然後保存在硬碟裡面;
4.當我們執行文件的時候,pycharm會調用python的解釋器來讀取文件,在py2中,預設會以ASCII將代碼解碼成unicode數據,但是ASCII碼並不認識中文,所以就會出現報錯。
File "E:/py/�ַ�����.py", line 2 SyntaxError: Non-ASCII character '\xe4' in file E:/py/�ַ�����.py on line 2, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
所以,在py2中,我們需要加上:
#coding=utf8 print("你好,世界!") #運行結果 你好,世界!
但是在py3中就不存在這個問題了,只要編碼的時候適用的是UTF-8,python3預設的編碼規範就是UTF-8,它會用UTF-8來將UTF-8的bytes數據解碼成unicode,然後在電腦終端顯示!