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

原文網址:http://blog.csdn.net/trochiluses/article/details/16825269python

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

 

 

前言:程序員

       若是密碼領域同樣,從明文到密碼是加密,從密碼到明文是解密。在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腳本以下:網絡

  1. #!/usr/bin/python  
  2.   
  3. string='個人'  
  4. print string  

運行腳本,提示信息以下:函數

 

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

 

出錯緣由:python默認採用ascii編碼,而中文編碼再也不ascii編碼可以表示的範圍以內,因此string沒法將「個人」做爲ascii編碼保存爲str類型。加密

 

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

 

  1. #!/usr/bin/python  
  2. #coding=gbk  
  3. string='個人'  
  4. print string<span style="font-size:14px;">  
  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. 

 

  1. #!/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<span style="font-size:14px;">  
  9. </span>  

這段代碼的輸出以下:
個人
鎴戠殑
鎴戠殑

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

另外,你有沒有以爲奇怪:爲何str類通過編碼和解碼之後的對象都是unicode呢?

答案:str.encode()實際上就等價於str.decode(sys.defaultencoding).encode().而sys.defaultencoding通常是ascii,它是不能用來編碼中文字符的。

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對象,或者相反。

來看下面這一行例子:

 

  1. #!/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<span style="font-size:14px;">  
  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命令,能夠查看與語言有關的環境變量:

 

  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中關於字符處理的出錯與解決辦法

 

問題一:

 

  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的編碼方式:

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


     2)重置變量 sys.defaultencoding 

 

 

  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

相關文章
相關標籤/搜索