python2編碼總結

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

 

# -*- coding:utf-8 -*-正則表達式

python2默認以ASCII編碼,可是在實際編碼過程當中,咱們會用到不少中文,爲了避免使包含中文的程序報錯,也是爲了符合國際通用慣例,通常將咱們的文件編碼設置爲utf-8格式。編程

設定編碼的格式有不少種,只要第一行或者第二行的聲明符合正則表達式 "coding[:=]\s*([-\w.]+)" 便可,通常的聲明方式爲#-*- coding:utf-8 -*-。post

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聲明,程序就不會報錯。編碼

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

str = "你好"
print str

  雖然以上寫法不會報錯,可是輸出的倒是亂碼,爲何呢?這就是下面要講的內容。spa

 

encode和decode.net

講解編碼和解碼以前,先來說講Unicode和utf-8的關係,推薦這篇博客給你們。code

能夠這樣來理解:字符串是由字符構成,字符在計算機硬件中經過二進制形式存儲,這種二進制形式就是編碼。若是直接使用 「字符串↔️字符↔️二進制表示(編碼)」 ,會增長不一樣類型編碼之間轉換的複雜性。因此引入了一個抽象層,「字符串↔️字符↔️與存儲無關的表示↔️二進制表示(編碼)」 ,這樣,能夠用一種與存儲無關的形式表示字符,不一樣的編碼之間轉換時能夠先轉換到這個抽象層,而後再轉換爲其餘編碼形式。在這裏,unicode 就是 「與存儲無關的表示」,utf—8 就是 「二進制表示」。
python2中字符串有兩種表示形式,str和unicode。str能夠理解爲上面這段話中的二進制編碼格式,unicode能夠理解爲抽象層。encode是編碼,即從unicode格式到二進制的編碼格式如utf-八、gb2312等。decode是解碼,即從二進制編碼格式到unicode編碼格式。
下面請看代碼:
# -*- coding:utf-8 -*-

str1 = "你好"
print type(str1)
str2 = str1.decode("utf-8")
print type(str2)

  str1是str類型, 經過decode轉爲了unicode類型。orm

下面看encode代碼:blog

# -*- 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編碼格式的字符。因此咱們要轉一下格式。

# -*- 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。使用方式大概以下:

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

import chardet

str = "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。如下內容引用自該篇文章:

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-八、GBK)。

 

以上爲最近編寫python代碼的過程當中遇到的一些問題及總結,若是有什麼不對的地方還請你們及時回覆交流,在此謝過。

相關文章
相關標籤/搜索