標籤:

python2編碼總結

以下依次列出python2常遇到的幾個問題及講解。

# -*- coding:utf-8 -*-

python2默認以ASCII編碼,但是在實際編碼過程中,我們會用到很多中文,為了不使包含中文的程序報錯,也是為了符合國際通用慣例,一般將我們的文件編碼設置為utf-8格式。

設定編碼的格式有很多種,只要第一行或者第二行的聲明符合正則表達式"coding[:=]s*([-w.]+)" 即可,一般的聲明方式為#-*- coding:utf-8 -*-。

12 str = "你好"print str

  運行以上代碼,程序會報錯:SyntaxError: Non-ASCII character "xe4" in file D:/TestPython/test/111.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details。這是提示程序中有非ASCII編碼的字元。如果加上utf-8聲明,程序就不會報錯。

1234 # -*- coding:utf-8 -*-str = "你好"print str

  雖然以上寫法不會報錯,但是輸出的卻是亂碼,為什麼呢?這就是下面要講的內容。

encode和decode

講解編碼和解碼之前,先來講講Unicode和utf-8的關係,推薦這篇博客給大家。

可以這樣來理解:字元串是由字元構成,字元在計算機硬體中通過二進位形式存儲,這種二進位形式就是編碼。如果直接使用 「字元串??字元??二進位表示(編碼)」 ,會增加不同類型編碼之間轉換的複雜性。所以引入了一個抽象層,「字元串??字元??與存儲無關的表示??二進位表示(編碼)」 ,這樣,可以用一種與存儲無關的形式表示字元,不同的編碼之間轉換時可以先轉換到這個抽象層,然後再轉換為其他編碼形式。在這裡,unicode 就是 「與存儲無關的表示」,utf—8 就是 「二進位表示」。python2中字元串有兩種表示形式,str和unicode。str可以理解為上面這段話中的二進位編碼格式,unicode可以理解為抽象層。encode是編碼,即從unicode格式到二進位的編碼格式如utf-8、gb2312等。decode是解碼,即從二進位編碼格式到unicode編碼格式。下面請看代碼:

# -*- coding:utf-8 -*-str1 = "你好"print type(str1)str2 = str1.decode("utf-8")print type(str2)

  str1是str類型, 通過decode轉為了unicode類型。

下面看encode代碼:

123456 # -*- coding:utf-8 -*-str1 = u"你好"print type(str1)str2 = str1.encode("utf-8")print type(str2)

  str1是unicode類型,通過encode轉為了str類型。

我們再回頭看最開始留下的問題,那段代碼為什麼會輸出亂碼呢。因為文件規定的編碼格式是utf-8,但是我們print是列印到控制台的,控制台無法顯示utf-8編碼格式的字元。所以我們要轉一下格式。

12345 # -*- coding:utf-8 -*-str = "你好"str = str.decode("utf-8")print str

  很多時候編碼解碼的時候需要加ignore參數才能正確轉換,例如.encode("utf-8", "ignore")或.decode("utf-8", "ignore"),大家自行斟酌吧。

chardet獲取編碼格式

有些時候我們是無法知道字元串是什麼編碼的,比如抓取網頁時,有些是utf-8的,有些是gb2312編碼的,那我們該怎麼獲取編碼格式並轉換為unicode呢。這裡就介紹到一個第三方庫chardet。使用方式大概如下:

1234567 # -*- coding: utf-8 -*-import chardetstr = "xxxxx"str_type = chardet.detect(str)code = str_type["encoding"]

  code即為str的編碼格式。但有些人反映該方法得到的編碼格式不準確,速度也慢。本人親測,速度確實一般,但是目前還沒遇到不準確的情況。大家可以斟酌使用,我這裡只是提供一個思路,如果誰那裡有更好的方式,可以告知小弟,不吝賜教才是。

import sys

reload(sys)

sys.setdefaultencoding("utf8")

之前也遇到過很莫名其妙的編碼錯誤,網上搜到這種方法能解決就糊裡糊塗的用上了,也不知是什麼原理。今天看到一篇不錯的博客,推薦給大家:http://blog.csdn.net/crazyhacking/article/details/39375535。以下內容引用自該篇文章:

12345678910111213141516171819202122232425262728293031323334353637 Python 裡面的編碼和解碼也就是 unicode str 這兩種形式的相互轉化。編碼是 unicode -> str,相反的,解碼就是 str -> unicode。剩下的問題就是確定何時需要進行編碼或者解碼了.關於文件開頭的"編碼指示",也就是 # -*- coding: -*- 這個語句。Python 默認腳本文件都是 UTF-8 編碼的,當文件中有非 UTF-8 編碼範圍內的字元的時候就要使用"編碼指示"來修正. 關於 sys.defaultencoding,這個在解碼沒有明確指明解碼方式的時候使用。比如我有如下代碼: #! /usr/bin/env python # -*- coding: utf-8 -*- s = "中文" # 注意這裡的 str 是 str 類型的,而不是 unicode s.encode("gb18030") 這句代碼將 s 重新編碼為 gb18030 的格式,即進行 unicode -> str 的轉換。因為 s 本身就是 str 類型的,因此 Python 會自動的先將 s 解碼為 unicode ,然後再編碼成 gb18030。因為解碼是python自動進行的,我們沒有指明解碼方式,python 就會使用 sys.defaultencoding 指明的方式來解碼。很多情況下 sys.defaultencoding 是 ANSCII,如果 s 不是這個類型就會出錯。拿上面的情況來說,我的 sys.defaultencoding 是 anscii,而 s 的編碼方式和文件的編碼方式一致,是 utf8 的,所以出錯了: UnicodeDecodeError: "ascii" codec can"t decode byte 0xe4 in position 0: ordinal not in range(128) 對於這種情況,我們有兩種方法來改正錯誤: 一是明確的指示出 s 的編碼方式 #! /usr/bin/env python # -*- coding: utf-8 -*- s = "中文"s.decode("utf-8").encode("gb18030") 二是更改 sys.defaultencoding 為文件的編碼方式 #! /usr/bin/env python # -*- coding: utf-8 -*- import sys reload(sys) # Python2.5 初始化後會刪除 sys.setdefaultencoding 這個方法,我們需要重新載入 sys.setdefaultencoding("utf-8") str = "中文"str.encode("gb18030")看完之後,改成這樣print "<p>addr:", form["addr"].value.decode("gb2312").encode("utf-8") 成功通過.

  但是這種方式用著就是彆扭,還是盡量自己來控制編碼,明確了編碼格式,自己寫著也踏實。

個人總結

實際編程過程中,最好能在代碼內統一編碼格式,比如統一為unicode,因為這樣就不用考慮編碼的問題了。到了顯示或輸出時再轉換為存儲類型(utf-8、GBK)。

以上為最近編寫python代碼的過程中遇到的一些問題及總結,如果有什麼不對的地方還請大家及時回復交流,在此謝過。


推薦閱讀:

編碼歪傳
業力與大腦神經編碼記憶 腦可塑性-大腦皮層增大-記憶學習經歷固化 大腦重構 關鍵期MeCP2蛋白 中風大腦修復
iOS KVO crash 自修復技術實現與原理解析
應該學習編碼的5個理由
URL編碼與解碼

TAG:編碼 | 總結 |