在討論python編碼之前,我先了解了幾種編碼的由來。
一、編碼類型
1、ascci碼
ascci碼由美國人發明,用1個字節(byte)存儲英文和字符,前期用了128個,后來新加了其他歐洲國家的符號,128~255這一段。
256個字符,基本上就是鍵盤上的所有字符。
2、unicode
2個byte,65535。因為后來發現還有其他國家的語言,而256個字符太少。
3、utf-8
UTF-8是Unicode的實現方式之一。
UTF-8最大的一個特點,就是它是一種變長的編碼方式。它可以使用1~4個字節表示一個符號,根據不同的符號而變化字節長度。
UTF-8的編碼規則很簡單,只有二條:
- 對於單字節的符號,字節的第一位設為0,后面7位為這個符號的unicode碼。因此對於英語字母,UTF-8編碼和ASCII碼是相同的。
- 對於n字節的符號(n>1),第一個字節的前n位都設為1,第n+1位設為0,后面字節的前兩位一律設為10。剩下的沒有提及的二進制位,全部為這個符號的unicode碼。
下表總結了編碼規則,字母x表示可用編碼的位。
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
4、GBK
GBK全稱《漢字內碼擴展規范》(GBK即“國標)就是國家制定的標准。
其實GBK在就是將每個漢字對應一個數字編碼,http://www.mytju.com/classCode/tools/encode_gb2312.asp 這個網址可以查看到具體的編碼對應關系:
比如:中國 二字,對應的各種編碼如下。
二、為什么要轉碼?
在python程序運行過程中,如果遇到編碼不一致(就好像中國人和美國人在一起,如果語言不通的話,就無法溝通。),就需要進行轉碼。相當於需要有一個翻譯。
在運行Python程序的過程中,會涉及到三個方面的編碼:
-
Python程序文件本身的編碼(test.py文件的編碼)--自身文件
- Python程序運行時環境的編碼(比如securecrt,類似mysql客戶端連接時的編碼)--客戶端
- Python程序讀取外部文件的編碼(引用外部文件的編碼)--外部文件
下面對於以上三種情況為什么需要轉碼分別進行說明:
情況一(自身文件編碼問題)
python2默認編碼為ascii,如果我們寫的代碼里面有非ascii字符,比如中文字符,py程序就會不認識。
就相當於兩個人都用普通話在溝通,其中某一個人突然蹦出一句家鄉話,另外一個人突然就懵逼了,同樣,python也懵逼了。
記得剛開始接觸python時,就碰到了經典錯誤,然后網上各種找資料,后來照着網上前輩們的設置,也沒有深究其原理。
經典錯誤范例:
#!/usr/bin/env python print '你好 大鳥'
運行時會報錯:
SyntaxError: Non-ASCII character '\xe4' in file t.py on line 4, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details
錯誤原因:python2默認的編碼為ascii,python3默認編碼為utf-8,而文件里面包含了非ASCII字符,所以他肯定不認識,就報錯了。
可以通過sys模塊查看默認編碼:
>>> sys.getdefaultencoding() 'ascii'
怎么解決?
針對情況一解決方法:(目的都是將默認編碼修改成utf-8,這樣,程序既可以認識ascii,又可以認識utf-8了)
解決方法一: import sys reload(sys) sys.setdefaultencoding('utf-8')
解決方法二: #coding:utf8
解決方法三: #-*- coding:utf-8 -*-
情況二(客戶端編碼問題)
我們在使用mysql時,如果客戶端設置為latin,而服務端為utf-8,查詢內容有中文時,就會出現亂碼。同樣,我們在使用python時,secureCRT也是客戶端,服務端就是我們連接的服務器。
范例:
1、客戶端設置secureCRT編碼為UTF-8
2、服務端測試
3、設置客戶端為非utf-8時,就會出現亂碼
結果如下:
而且從步驟2中也可以看出,python自動識別變量a='中國test'為utf-8的編碼,如果客戶端(secureCRT)和服務端(python)編碼不一致時,就會出現亂碼。
情況二解決辦法:設置客戶端的編碼格式和服務端一致!
情況三:讀取外部文件時,出現亂碼
比較典型的就是:當我們從windows上編輯一個文件,上傳到linux上時,會驚奇的發現^M符號。這個就是因為windows和linux的回車換行符不一致導致的,此時如果是python文件時,python也會報錯。
我們在linux先查看時會有特殊符號:
這時,如果我們需要去掉^M,需要使用dos2unix工具轉換一下,去掉windows上的格式。
三、編碼怎么轉換
unicode為橋梁,utf-8和gbk互轉需要經過unicode這個翻譯,不然他們二者是無法直接溝通。
操作范例:
1、查看默認編碼,python遇到中文字符,會識別他是utf-8編碼,chardet模塊可以識別編碼格式,但是也不是100%,下面他識別出myname為utf-8的概率為75%。
2、將utf-8轉為unicode編碼
utf-8轉為unicode編碼是,需要指定他本身是什么格式的編碼,類似於加密。查看myname_unicode變量時,發現他是unicode編碼格式了。
3、將unicode編碼轉為utf-8
具體轉換操作如下:
例子:
>>> a=u'中國' #unicode編碼格式的字符串 >>> a_utf8=a.encode('utf-8') #將unicode轉成utf-8編碼格式 >>> a_utf8 '\xe4\xb8\xad\xe5\x9b\xbd' >>> a_unicode=a_utf8.decode('utf-8') #從utf8編碼格式轉回unicode編碼格式 >>> a_unicode u'\u4e2d\u56fd' >>> a u'\u4e2d\u56fd' >>>
>>> b_gbk=a_unicode.encode('gbk') #將上面unicode格式的轉成gbk編碼格式 >>> b_gbk '\xd6\xd0\xb9\xfa' >>> b_unicode=b_gbk.decode('gbk') #轉回unicode編碼格式 >>> b_unicode #最后發現,a_unicode、b_unicode和原始的unicode編碼的a都相等。 u'\u4e2d\u56fd' >>> a_unicode u'\u4e2d\u56fd' >>> a u'\u4e2d\u56fd' >>>
a.encode(* *):將a 編碼 為 * *編碼格式的字符串或unicode對象
a.decode(* *):將a 解碼 為 unicode編碼格式的字符串或unicode對象
另外:
Python將字符串格式的unicode編碼轉換成unicode編碼,如:\u53eb\u6211,需要轉換成中文時有兩種方式
1.使用eval:
eval("u"+"\'"+unicodestr+"\'")
2.使用decode:
str1 = '\u4f60\u597d' print str1.decode('unicode_escape') 你好
unicodestr.decode('unicode_escape') # 將轉義字符\u讀取出來
四、參考文獻和文件索引
1、漢字對應表:http://www.chi2ko.com/tool/CJK.htm
2、阮一峰的網站