python 字符編碼與解碼——unicode、str和中文:UnicodeDecodeError: 'ascii' codec can't decode 分類: python

轉自:http://blog.csdn.net/trochiluses/article/details/16825269


摘要:在進行python腳本的編寫時,如果我們用python來處理網頁數據或者進行與中文字符有關的處理工作,經常出現這樣的出錯信息:SyntaxError: Non-ASCII character '\xe6' in file ./filename.py on line 3, but no encoding declared。本文主要講解python中與unicode和中文、特殊字符編碼有關的問題。字符編碼和解碼需要遵循什麼規律?


前言:

       如果密碼領域一樣,從明文到密碼是加密,從密碼到明文是解密。在python中,編碼:unicode-->str;解碼str-->unicode.既然是編碼,那麼就和密碼領域一樣,編碼和解碼自然涉及到編碼/解碼方案(對應加密或者解密算法),unicode相當於明文。在python中,編碼函數是encode(),解碼函數是decode()。需要注意的一點是,如果我們調用str.encode(),這裏涉及到一個隱士的類型轉化,會現將str轉化成unicode,才能進行編碼,這也是不太容易理解的地方。所以,str.encode()實際上就等價於str.decode(sys.defaultencoding).encode().而sys.defaultencoding一般是ascii,它是不能用來編碼中文字符的。

     在閱讀本文之間,如果你對字符編碼不是很熟悉,有必要先了解以下字符編碼。可以參考:字符編碼簡介

1.一箇中文字符編碼問題


一個python腳本如下:

[python] view plaincopy
  1. <span style="font-size:14px;">  #!/usr/bin/python  
  2.     
  3.   string='我的'  
  4.   print string</span>  
運行腳本,提示信息如下:

SyntaxError: Non-ASCII character '\xe6' in file ./filename.py on line 3, but no encoding declared


出錯原因:python默認採用ascii編碼,而中文編碼不再ascii編碼能夠表示的範圍之內,所以string無法將“我的”作爲ascii編碼保存爲str類型。


解決辦法:採用中文字符編碼,在腳本第二行加入編碼類型,如下:

[python] view plaincopy
  1. <span style="font-size:14px;">#!/usr/bin/python  
  2. #coding=gbk  
  3. string='我的'  
  4. print string  
  5. </span>  

這裏,coding同樣可以採用utf-8等能夠編碼中文字符的模式。

2.python的對字符的編解碼

字符編碼/解碼函數:

 1)unicode:這個是python的內建函數,位於unicode類。

unicode(string [, encoding[, errors]]) -> object

這個函數的作用是將string按照encoding的格式編碼成爲unicode對象。

省略參數將用python默認的ASCII來解碼


2)decode:位於unicode類中。

 decode(...)
 |      S.decode([encoding[,errors]]) -> string or unicode

 |      
 |      Decodes S using the codec registered for encoding. 


[python] view plaincopy
  1. <span style="font-size:14px;">#!/usr/bin/python  
  2. #coding=gbk  
  3. string='我的'  
  4. print string  
  5. s1=unicode(string,"gbk")  
  6. s2=string.decode("gbk")  
  7. print s1  
  8. print s2  
  9. </span>  
這段代碼的輸出如下:
我的
鎴戠殑
鎴戠殑

顯然,輸出好像沒有達到我們的期許的結果。爲什麼s1和s2輸出的是亂碼呢?string是str,print輸出到屏幕,這個終端採用的字符編碼有關。爲什麼string是正常的,而s1和s2都是亂碼呢?我們接下來分析.


3)decode和encode都可以用於常規字符串和unicode字符串

但是:

     str.decode()和unicode.encode()是直接正規的使用。

     unicode.decode()會先將unicode轉化成str,然後再執行decode()。


3.codec是什麼


Codec是把Coder/DECoder得首字母組合,它定義了文本跟二進制的轉換方式,跟ASCII那種用一個字節把字符轉換成數字的方式不同,Unicode用的是多字節,這導致了Unicode支持多種不同的編碼方式,比如說codec支持的四種耳熟能詳的編碼方式是:ASCII,ISO8859—1/Latin-1,UTF-8,和UTF-16


最著名的是UTF-8編碼,它也用一個字節來編碼ASCII字符,這讓那些必須同時處理ASCII碼和Unicode碼文本的程序員的工作變得非常輕鬆,因爲ASCII字符的UTF-8編碼和ASCII編碼完全相同。


UTF-8編碼可以用1到4個字節來表示其他語言的字符,這給那些需要直接處理Unicode數據的程序員帶來了麻煩,因爲他們沒有辦法按照固定長度逐一讀出各個字符,幸運的是我們不需要掌握直接讀取Unicode數據的方法,Python已經替我們完成了相關細節,我們無需爲處理多字節字符的複雜問題而擔心。

UTF-16也是一種變長編碼,但是它不常用。


4.編碼與解碼

Unicode支持多種編碼格式,這爲程序員帶來了額外的負擔,每當你向一個文件寫入字符串的時候,你必須定義一個編碼用於把對應的Unicode內容轉換成你定義的格式,Python通過Unicode字符串的encode()函數解決了這個問題,該函數接受字符串中的字符爲參數,輸出你指定的編碼格式的內容。


所以,每次我們寫一個Unicode字符串到磁盤上我們都要用指定的編碼器給他“編碼“一下,相應地,當我們從這個文件讀取數據時,我們必須”解碼”該文件,使之成爲Unicode字符串對象。


5.python對unicode的支持


內建的unicode()函數:將一個string類型的字符串轉變成一個unicode對象

decode/encode方法:用於將str對象轉化成unicode對象,或者相反。

來看下面這一行例子:

[python] view plaincopy
  1. <span style="font-size:14px;">#!/usr/bin/python  
  2. #coding=gbk  
  3. string='我的'  
  4. print "string is:",type(string)  
  5. print string  
  6.   
  7. ustring=u"我的"  
  8. print "ustring is:",type(ustring)  
  9. print ustring  
  10.   
  11. gbkstring=ustring.encode("gbk")  
  12. print "gbkstring is:",type(gbkstring)  
  13. print gbkstring  
  14.   
  15. anotherstring=gbkstring.decode("gbk")  
  16. print "anotherstring is:",type(anotherstring)  
  17. print anotherstring  
  18. </span>  


輸出結果如下:


string is: <type 'str'>
我的
ustring is: <type 'unicode'>
鎴戠殑
gbkstring is: <type 'str'>
我的
anotherstring is: <type 'unicode'>
鎴戠殑


任何兩種字符編碼之間如果想完成轉化,必須要通過unicode這個橋樑,先把它抓化成unicode對象;unicode對象直接進行輸出,往往會出現亂碼,需要解碼成str對象。另外需要注意:unicode對象,gbk編碼,ascii編碼,str對象這四個不同的概念。注意區分什麼是字符串類型,什麼是編碼類型。


6.注意事項


關於字符編碼的原理,可以參考這裏:

在python中需要使用unicode需要注意:


   1 程序中出現字符串時一定要加一個前綴u

   2 不要用str()函數,用Unicode()代替

   3 不要用過時的string模塊。如果傳給它非ASCII碼,它會把一切搞砸。

   4 不到必須時不要在你的程序裏編解碼Unicode字符,只在你要寫入文件或者數據庫或者網絡時,才調用encode()函數和decode()函數。

   5.使用什麼字符編碼,就要採用對應的字符集進行解碼


內建的str()函數和chr()函數不能處理Unicode,它們只能處理常規ASCII編碼的字符串,如果一個Unicode字符串作爲參數傳給了str()函數,它會首先被轉換成ASCII碼字符串然後交給str()函數。


7.關於linux終端的字符編碼

終端等默認語言設置在/etc/environment之中,在linux下,如果terminal採用的是utf-8編碼,那麼如果我們的中文采用gbk編碼,很有可能在輸出到屏幕的時候產生亂碼。

使用locale命令,可以查看與語言有關的環境變量:

[python] view plaincopy
  1. hyk@hyk-linux:~/program/python/chapter6  
  2. $ locale  
  3. LANG=zh_CN.UTF-8  
  4. LANGUAGE=zh_CN:en_US:en  
  5. LC_CTYPE="zh_CN.UTF-8"  
  6. LC_NUMERIC=zh_CN.UTF-8  
  7. LC_TIME=zh_CN.UTF-8  
  8. LC_COLLATE="zh_CN.UTF-8"  
  9. LC_MONETARY=zh_CN.UTF-8  
  10. LC_MESSAGES="zh_CN.UTF-8"  
  11. LC_PAPER=zh_CN.UTF-8  
  12. LC_NAME=zh_CN.UTF-8  
  13. LC_ADDRESS=zh_CN.UTF-8  
  14. LC_TELEPHONE=zh_CN.UTF-8  
  15. LC_MEASUREMENT=zh_CN.UTF-8  
  16. LC_IDENTIFICATION=zh_CN.UTF-8  
  17. LC_ALL=  

python的print方法,會自動將相關的字符編碼,轉化成該環境變量對應的字符編碼,所以使用print 可能會出現亂碼和報錯;但是使用write卻不會。


8.python中關於字符處理的出錯與解決辦法


問題一:

[python] view plaincopy
  1. 13 strencode=string.encode("utf-8")  
  2. 14 print "strencode is : ",type(strencode)  
  3. 15 print strencode  


UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 4: ordinal not in range


解釋:str本身是不能encode的,如果想要encode,先要轉化成unicode,此時採用默認的ascii進行轉化,所以就出錯了。

解決辦法:

1)指明str轉化成unicode的編碼方式:

[python] view plaincopy
  1. #! /usr/bin/env python     
  2. # -*- coding: utf-8 -*-     
  3.     
  4. s = '中文'     
  5. s.decode('utf-8').encode('gb18030')     

     2)重置變量 sys.defaultencoding 

[python] view plaincopy
  1. import sys     
  2. reload(sys) # Python2.5 初始化後會刪除 sys.setdefaultencoding 這個方法,我們需要重新載入     
  3. sys.setdefaultencoding('utf-8')     
  4.     
  5. str = '中文'     
  6. str.encode('gb18030')    


參考文獻:

【1】字符編碼簡介:http://blog.csdn.net/trochiluses/article/details/8782019

發佈了13 篇原創文章 · 獲贊 7 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章