Python2 新手 編碼問題 吐血總結

什麼是編碼

  任何一種語言、文字、符號等等,計算都是將其以一種相似字典的形式存起來的,好比最先的計算機系統將英文文字轉爲數字存儲(ASCII碼),這種文字與數字(或其餘)一一對應的關係咱們稱之爲編碼。因爲ASCII碼只包含了大小寫英文字母、數字和一些符號,顯然當計算機推廣到世界以後隨着語種增多,這套編碼並不適用,因而中國針對中文推出了GB2312碼,可是多語言時,又不行了,因而就出現了強大的Unicode(萬國碼)。可是因爲Unicode存儲性能問題,在純英文時存儲效率要遠低於ACSII碼,因而又出現瞭如今的UTF-8編碼(8-bit Unicode Transformation Format),能夠看作是Unicode的增強版,經過可變長度的編碼來使存儲最優,並且UTF-8編碼包含了ASCII碼,這一點很是重要。
  python處理文本時的中間編碼爲Unicode,因而就有了decode和encode,前者將unicode之外的字符串解碼爲unicode,後者將unicode編碼爲指定編碼。python

當你輸入字符串時

  首先,當你在python代碼中輸入一個字符串時候,它是以什麼編碼形式被保存的呢?linux

1.若是輸入了一串純英文,數字,或英文狀態下的標點符號,那麼不管有沒有在代碼最前面作編碼申明(如"# -- coding:utf-8 --"),字符串都是由ASCII碼存儲的,緣由很簡單,ascii碼只支持英文,佔用性能與空間小。git

  • 此時,該字符串能夠隨意decode(解碼)和encode(編碼),不會報錯,甚至不會進行任何變更,永遠都是ascii碼,type類型是str
  • 若是在輸入該字符串時加入了Unicode申明,即 u"balabala",那麼此時字符串type格式爲Unicode,能夠隨意encode,不可decode,可是不管encode成什麼,python仍是都會以ascii的形式存儲

2.若是輸入了中文,那麼狀況一會兒就變得複雜起來。此時必須進行編碼申明,不然會拋出以下錯誤:「Non-ASCII character '\xe5' in file **,but no encoding declared」,意思就是你輸入了ASCII碼沒法識別的東西,且沒有進行編碼申明,因此此時要在文件開頭進行編碼申明,完整版以下:github

#!/usr/bin/python
# -*- coding: <encoding name> -*-

  此時 處填上編碼方式,不區分大小寫,其實只寫下面一行就好了,上面一行只是爲了在linux系統裏識別而已。不少人對這種在註釋中進行申明的方式很不習慣,也不解-*-是什麼鬼,可是 PEP 263告訴咱們,這樣只是爲了好看而已。。。 編程

  • 舉個例子,若是你申明瞭utf-8編碼,那麼你輸入的任何帶有非英文(以及符合)非數字的字符串,都是utf-8編碼,咱們能夠經過 .decode('utf-8')的方式將其解碼爲Unicode碼方便python處理,注意此時不只其編碼編程Unicode,其類型也從str變成了Unicode。固然也可使用unicode(string,'utf-8')的方式來將其解碼爲unicode,Unicode函數與str函數的區別是前者嘗試用給定編碼(不給定時用ASCII)進行decode,然後者嘗試用ASCII(defaultencoding)進行encode,因爲ASCII碼被utf-8碼包含,因此對於utf-8字符串,進行str()是沒有問題的,可是對於其餘編碼文本進行str()則會報錯或是亂碼。
  • 若是輸入字符串時進行Unicode申明,如a=u"楊睿很帥",那麼此時字符串編碼直接爲unicode。可隨意進行encode,不可decode,不可str。

注意

1.chardet庫的detect方法能夠獲得字符串的編碼類型,當輸入字符串爲unicode時程序報錯,有時候也會誤判,置信水平小魚0.7則不可輕信了。c#

2.上述只針對在非DOS中執行py文件時適用:若是是在IDLE中單步執行,則中文字符串是以系統默認編碼(windows-1252)保存;若是是在DOS界面中運行,則爲GBK編碼,並且中文也必須是GBK編碼纔可正常顯示,不然報錯。windows

3.選擇一款好的IDE,設置一款獨特的凸顯品味的字體與配色,可以讓初學者前期愉快地被編碼問題搞崩,而不是惱火地崩掉,也能幫助你很好的管理代碼。(推薦PyCharm,有免費版)函數

設置默認編碼

import sys
reload(sys)
sys.setdefaultencoding( "utf-8" )

  以上代碼將系統編碼由ASCII碼轉爲UTF-8編碼。reload(sys)是由於import時將setdefaultencoding()方法刪除了,因此將其從新載入回來。爲何說ascii是系統默認編碼,由於當你使用str()給字符串encode或者是unicode()來decode時,都是默認使用了ASCII碼,所以常常會報出相似"UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 0"的錯誤,緣由就是字符串裏摻雜了中文,前面說到ascii碼是不支持中文的。若是把系統默認編碼設置爲utf-8,就不會出現這樣的問題了哦~
  那麼,它與腳本開頭的"# -*- coding:utf-8 -*-"有什麼區別呢,注意,腳本開頭的編碼申明只是針對在腳本中輸入的非英文、數字、符號的字符串如中文,將其存成utf-8的形式,而非系統轉碼的形式。
  當開頭設置默認編碼時,很容易出現程序運行到setdefaultencoding就默認終止的狀況(IDLE下),這時候須要在reload先後加入這個,目的是爲了從新定向,防止reload將變量重置:性能

stdout = sys.stdout
reload(sys)
sys.stdout = stdout

IO時的編碼問題

  • txt
      1.寫txt文件時,windows下默認會寫出爲ANSI編碼,在windows系統下就是GBK編碼。若是字符串被encode爲utf-8,那麼寫出的txt則爲utf-8,可是當字符串爲unicode時,若是有中文,寫出會報錯,緣由就是按照系統默認編碼ascii進行編碼了,按以前所說的將默認編碼改成utf8就沒問題了,但輸出的也變成了utf-8。若是想寫入unicode,須要藉助codecs庫的open方法,讀者能夠自行百度。
      2.讀取txt文件時,若是txt文件爲ANSI碼,則讀入的爲gbk編碼,可用gbk解碼;若是txt文件爲utf-8編碼,則讀入的也爲utf-8編碼;而若是txt爲unicode時,咱們會發現一個奇怪的現象,讀入的文本編碼變成了"utf-16",因此須要用utf-16解碼(至於爲何留給讀者探索)。
  • csv
      寫出csv時,注意utf-8編碼和gbk編碼是不能用製表符\t進行分列的(excel顯示時),必須使用逗號,不然沒法顯示分列結果。windows下推薦用gbk寫出,不然中文容易亂碼。固然,若是是包含大量文本的數據,很是不推薦使用csv輸出,一不當心就錯位,直接輸出excel是不錯的選擇。
  • excel
    xlrd,xlwt,xlsxwriter都是很是好的excel讀寫庫,xlrd目前支持讀寫xlsx(2007版)與xls(2003版),xlwt只支持寫出2003版xls,xlsxwriter支持2007版的寫出,並且輸入字符串均須要時unicode編碼才行,不然報錯。

網頁抓取時的編碼問題

  網頁抓取時遇到的主要問題,無非是網頁源代碼中摻雜了爲被轉義的編碼形式,被做爲純文本讀了進來,好比這樣一個字符串"\u6768\u777f",不管怎麼print 它都是這個形式由於它是文本,不是編碼,那麼怎麼轉爲中文呢,則須要用以下命令:字體

print text.decode('unicode_escape')

  很是生動形象的,這句話至關因而把「逃離」掉的unicode編碼進行再編碼,因而就獲得了咱們想要的中文。
  
  一樣,有的網頁中的文字是以反斜槓加三個數字形式呈現的,這個是標準的八進制字符串,如"\345\244\247",則表示一箇中文字;而utf-8的表現形式爲16進制字符串,像"\xe6\x9d\xa8"就表明着一個字 ,對於這些字符,只須要使用以下命令便可從文本轉爲編碼字符串:

print text.decode('string_escape')

可是,python使用中還有諸多編碼問題,在此推薦個人好友何燕傑的腳本解釋型語言Cygnus,目前整個語言正處於開發與調試階段,完善後將會在博客園裏給出。我爲此開源項目貢獻了很是簡潔易用、強大的爬蟲庫(Requests),因爲和c#完美對接,幾乎沒有任何編碼問題。你們敬請期待!

本博原創做品僅供品讀,歡迎評論,未經本人贊成謝絕轉載。特此申明!

相關文章
相關標籤/搜索