python學習:編碼中遇到的問題原因及解決方案

最近學python,2跟3版本的都有用到,兩者在編碼上還有點區別,特地查了點資料,自己歸納整理一下。可能會有點小錯誤,歡迎大家一起討論~


一、首先明確一下幾大編碼格式:

ASCII        #1個字符佔用1個字節

GBK         #專門用來編碼漢字,是GB2312的擴展,增加了繁體字、日文的假名等

Unicode   #2個字節

utf-8         #英文1個,中文3個字節(它是unicode的實現方式之一)


最早的編碼是ASCII,美國人發明的,包含大小寫英文字母、數字0-9(這裏的0-9是字符,即‘0’與0不同)和一些特殊符號共127個符號,佔用空間1個字節(8位二進制)。因爲ASCII碼不包含中文,所以誕生了GB2312,專門用來編碼中文,後來完善爲GBK。當然,基本每個國家都會針對自己的語言開發一套編碼,所以爲了將各個國家的編碼統一起來,不致於交互時出現亂碼,Unicode誕生了(內部統一了ASCII和GBK等編碼)。Unicode編碼了幾乎所有的字符,但他只是代表了編碼標準(具體的實現形式仍是GBK、ASCII等)。unicode一個字符大概佔用2個字節(生僻的需要3、個/4節),這在英文字母較多的情況下會佔用過多的空間,這是不能容忍的,所以又誕生了utf-8,utf-8將英文字母還按一個字節編碼,將中文編碼成3個字節,節省了空間。基本可以說utf-8是Unicode的存儲實現方式。


以上我們可以看出,

①ASCII、GB2312、GBK、unicode是向下兼容的,後面的編碼內部都含有前面的編碼,所以用後面的編碼對前面的進行解碼不會出現亂碼。

②而utf-8編碼的文件使用GBK解碼時,如果不聲明則會出現亂碼的情況。


二、python2和系統內部編碼

明確以下幾點:

1、區分decode(解碼)和encode(編碼)

簡單來說,就是一個字符,要保存的時候,就用encode按照選擇的編碼規則保存,要讀取的時候,就用decode按照選擇的編碼規則來解碼讀取。

如果現在一個字符a是GBK格式,那要讀取他就需要使用a.decode('gbk')來解碼。

要將一個GBK格式保存的字符轉換成utf-8保存,就需要先解碼再編碼,即a.decode('gbk').encode('utf-8')。知道了這些後再來看看以下幾點:

①計算機內存統一採用Unicode編碼。當需要保存到硬盤或傳輸(如網頁內容)的時候,就轉成utf-8(這就是上文說到的utf-8是Unicode的存儲實現形式的原因,當讀取到內存的時候,編碼爲Unicode,需要保存時則採用utf-8)

②windows系統下cmd執行時,採用的是gbk解碼。

③寫代碼的記事本如sublime、notepad本身保存代碼是有個默認編碼格式的,一般爲utf-8。

④python2的交互操作界面默認對中文采用gbk編碼和解碼。

⑤python的默認解碼方式(decode)是ascii,因爲ASCII編碼中不存在中文,所以內部含有中文的時候會拋出異常;默認編碼方式(encode)是unicode


知道了上述的編碼和解碼規則之後我們就能解決大部分的python2亂碼問題了。


2、編碼規則聲明和實際問題解決

大部分人編寫代碼通常是採用的sublime或notpad等記事本編輯代碼腳本,然後保存,(只要保存就肯定要以某種編碼形式存儲代碼),然後在cmd或者交互界面下執行(這時有解碼)。

而python在讀取源代碼文件時,不聲明情況下,默認是用ASCII解碼,所以存在中文時就容易拋出異常。所以通常我們會在文本文件的開頭加上#-*- coding utf-8 -*-  ,表示文本內部採用utf-8的編碼規則,python解碼的時候則也使用utf-8解碼。但是仍然會遇到問題如:

腳本文件:

# -*- coding:utf-8 -*-
a='你好'
print a
print repr(a)   #打印a的編碼值

cmd下結果:


可以看出用utf-8編碼的文本在cmd命令行下運行得到的是亂碼,這就是咱們前面提到的cmd下是使用的gbk規則,要解決這種衝突主要有以下幾種辦法:

①將文本的保存格式改爲gbk,同時將聲明改爲gbk如 #-*- coding:gbk -*-                

                                                                                  #不推薦,因爲utf-8的應用較廣泛,通常還特地將文本保存成utf-8 

②將語句改爲print a.decode('utf-8').encode('gbk')    #較麻煩 

③將中文字符聲明爲unicode格式,a=u'啊哈'            #最常用的做法


結果(編碼已被改爲gbk):


此外,python默認會對字符先採用decode,再encode,未聲明時則使用默認的de和en格式,如下:

<span style="font-size:14px;">#-*- coding:utf-8 -*-
s = "你好"
s.encode('gbk')    #默認先用ascii來decode
s.decode('utf-8')   #默認最後用unicode來encode</span>

以上語句在真正執行的時候s.encode('gbk')會報錯,因爲其默認decode方式爲ascii,對中文不支持。這也是經常導致編碼出錯的原因之一。



三、python常見的其他編碼問題

看了上文的介紹,基本可以知道出現亂碼的情況就是編碼規則的不同導致的。

接下來說說我這幾天遇到的編碼問題:

①在python2裏,通常只要聲明unicode之後都能正常打印,但是有個例外就是input函數,input函數誇號裏要是加入了中文字符的話必須使用上面提到的第二種方法進行操作否則會拋出亂碼:

a=input('請輸入數字:'.decode('utf-8').encode('gbk'))   #不添加後面的decode,encode,字符串‘請輸入數字’將在屏幕上顯示爲亂碼
②通常我們從網頁上獲取數據或爬取數據的時候,網頁的編碼格式都是採用的utf-8,所以爬取下來的數據通常要採用utf-8解碼,轉成字符串str,否則經常會在後續出現亂碼的情況:

content=response.read().decode('utf-8')


四、瞭解python中的str字符串對象和編碼區別

查了點資料,自己歸納理解了一下。我覺得首先str應該算是一種在執行中生成的字節流,他本身不具有固定的編碼格式,他的具體編碼格式由聲明來確定,如下:

#-*- coding:utf-8 -*-
a='你好'

如果以上語句被保存爲一個腳本文件,那麼這個時候a便是採用的utf-8來編碼。

如果在python交互界面中輸入a='你好',則a默認採用交互界面的默認編碼格式。

綜上所述,str是一種字節流,沒有其他含義,而編碼則是一種對文本包括字符串的編碼格式。我們可以把具有unicode編碼格式的字符串看做字節流,但是不能隨意把他當做unicode字符串來看。



五、python2跟3的區別

python2裏把編碼分爲unicode和非unicode,python3則統一採用unicode保存,所以3對中文的支持特別好,很多時候不用刻意進行轉碼,如上面的input問題在3中就幾乎不用進行轉碼


以上。

剛開始接觸編碼,要是有哪裏寫的不對的,大家多給我提提哈,互相學習~大笑



參考資料:

http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431664106267f12e9bef7ee14cf6a8776a479bdec9b9000

http://www.cnblogs.com/ymy124/archive/2012/06/23/2559282.html

http://www.server110.com/python/201402/6393.html

http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章