在用python程式設計中,字串有兩種表示方法"string"和 u"string"。為什麼字串要是用這兩種表達方式,不是只用前一種呢?
使用type()函式檢視,它們分別是str物件和unicode物件。這兩個物件有什麼區別嗎?還有經常用到的encode()和decode()又是幹什麼的呢?都說python指令碼使用的是兩位元組編碼,這又是指什麼呢?
要回答上面幾個問題,首先得弄清楚關於編碼的幾個概念:
character set:字符集,是我們人可以識別的字元。如ascii規定了127個用乙個位元組可以表示的字符集,包括英文本母、數字、符號和一些控制字元。當然ascii定義的字符集比較小。python中的character set基本包括目前世界上所有是用的字元,如中文、英文、日文字元等等。所以基本上所有的字元都可在python 中進行處理。code point:計算機是不能直接識別字元的(因為它只能直接識別二進位製碼),所以為了能讓計算機處理和儲存字元,需要將字元對映成乙個數值(因為數值可以用二進位制表達,計算機從而就可以識別了),這個數值叫作字元的code point。字元與其code point是一對一對映,unicode很好的規定了這種對映關係。
encode:unicode雖然規定了每個字元的code point,但並沒有規定計算機如何儲存這些code point。所有就有了utf-8、gbk、utf-16等編碼格式,它們規定計算機如何來儲存這個code point,每個編碼格式它們儲存方式都是不相同的。例如,「中」字的code point為u
+2d2e(u表示unicode,2d2e表示該code point值),使用gbk、big5、utf-8、utf-16四種編碼協議對該code point進行編碼,獲得的實際二進位制表示如下:
gbk big5 utf-8 utf-16
~~\xd6\xd0 \xa4\xa4 \xe4\xb8\xad \x2d\x4e
decode:對實際的二進位制進行解碼,獲取它所代表字元的code point。如「\xd6\xd0」使用gbk解碼,將獲得2d2e(「中」的code point ),如果使用utf-8對其進行解碼,就會出錯,因為它不是用utf-8編碼的。
上面簡單介紹下字元及編碼解碼的概念,可參考博文《字元的編碼與解碼》。
python中使用兩種字串表達方式,是為了區分字元與實際表示字元的二進位制資訊。unicode物件用來表示字元,它不涉及字元的底層的二進位制編碼資訊。str物件是用來表示字元的二進位制資訊。乙個unicode物件可以使用多種編碼格式(如utf8、gbk)編碼(encode)成多個str物件,每個str物件表示該字串的一種二進位制表達。多個不同的str物件可以解碼成相等的unicode物件(表示字串相同,但記憶體位置不同)。
unicode的存在也是為了解決因採用不同編碼格式導致的一些問題,建議大家使用unicode物件來存放字串,統一格式。unicode雖然不規定具體的二進位制資訊,但為了存放每個字元的code point值,需要兩個位元組,所以說python採用的是二進位制編碼(不知道這麼理解可對?)。
由於str物件沒有屬性指定它的編碼格式,所以對它進行處理時,只能將它看成乙個位元組串。當對str物件進行列印或解碼時,且不知道它的編碼格式,那麼python只能用預設編碼格式對其進行操作。如果編碼不匹配,就會出現亂碼或者報錯。
str物件:
稱字串,它是字串使用特定編碼格式進行編碼後的二進位制表達,實際代表用於儲存二進位制資訊的位元組串。所以稱它為「位元組串」更合適。如unicode物件:>>> str = '你好' #採用系統設定的編碼格式對「你好」進行編碼,可通過locale命令檢視。
>>> str
'\xe4\xbd\xa0\xe5\xa5\xbd' #當locale設定為utf8時,'你好'的編碼後的二進位制表達,乙個六位元組的位元組串
用於表達「字元」,因為計算機不用直接識別字元,所以使用code point來代替字元。如下:>>> u"你好"
u'\u4f60\u597d'
code point 4f60表示「你」,597d表示「好」。它只是乙個數值與字元對映,不用於具體編碼。
對乙個str物件進行解碼,可以獲得它表達字串的code point,即unicode物件。對unicode物件進行編碼,可獲得它的實際二進位制表達,即str物件。當想把str物件從一中編碼格式轉換成另一種編碼格式時,首先得把str轉換成unicode物件,再從unicode物件轉換成另外一種編碼格式的str物件。下面執行乙個str物件從utf8格式到gbk格式的轉換:
>>> str="你好"
>>> str
'\xe4\xbd\xa0\xe5\xa5\xbd' # 採用os的utf8編碼格式
>>> unicode=str.decode("utf8") # 解碼成code point值
>>> unicode
u'\u4f60\u597d'
>>> str_gbk=unicode.encode("gbk") # 將code point編碼成gbk格式
>>> str_gbk
'\xc4\xe3\xba\xc3'
>>> unicode.encode() # 如果編碼不指定格式,將採用系統預設的編碼格式進行編碼。對於decode也一樣。這裡由於ascii不能對中文字元編碼,所以出錯了。
traceback (most recent call last):
file "", line 1, in unicodeencodeerror: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
>>> u = u"你好" #字首u自動把字串從utf8轉換成unicode格式了
u'\u4f60\u597d'
寫檔案:
>>> file=open("test.txt", "a")
>>> file.write(str)
>>> file.write(str_gbk)
>>> file.write(unicode)
traceback (most recent call last):
file "", line 1, in unicodeencodeerror: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
從上面看,utf8格式的str物件和gbk格式的str物件成功的寫入test.txt檔案,然而在將unicode物件寫入檔案時,出現錯誤了。這是為什麼呢?
str物件表示字串經編碼後的二進位制資訊,可以直接寫入檔案。然後unicode物件表示的是字串的code point值,是抽象的值,用來表示字元,是不能直接寫入檔案的。所以python試圖使用預設的編碼格式ascii,對unicode物件進行編碼,然後將結果存入檔案。但是由於ascii不能對」你好」進行編碼,所以報錯了。
修改系統預設編碼格式:
>>> import sys
>>> reload(sys)
>>> sys.setdefaultencoding("gbk") #不建議這麼用[2]
>>> str(unicode) #使用預設gbk,對unicode("你好")進行編碼,轉成str物件
'\xc4\xe3\xba\xc3'
>>> unicode.encode() #使用預設gbk,對unicode("你好")進行編碼,轉成str物件
'\xc4\xe3\xba\xc3'
>>> "你好".decode() #因為系統使用utf8,所以「你好」是utf8格式的位元組串,使用預設gbk對該位元組串進行解碼,雖然成功執行了,但其結果是不正確的。所以我們需要保證位元組串用什麼格式編碼的,就要用什麼格式解碼。
u'\u6d63\u72b2\u30bd'
[1]
[2]
[3]
[4]
python字元編碼
ascii 碼是乙個位元組,通常只能顯示英文本母和數字。unicode碼為了顯示多種語言產生,但是要占用兩個位元組,顯示文字要占用大量空間 utf 8 為了節約空間而生,英文本元只用乙個位元組儲存,中文字元需要三個位元組 character ascii unicode utf 8 a01000000...
python字元編碼
列印python檔案編碼 import sys print sys.getdefaultencoding 中文的乙個字元unicode占用2個位元組。對在於ascii字元占用1個位元組 utf 8中 中文字元佔3個位元組,英文本元占用1個位元組 編碼和轉碼 unicode不能再解碼了 它是基層的 u...
Python字元編碼
在用python程式設計中,字串有兩種表示方法 string 和 u string 為什麼字串要是用這兩種表達方式。不是僅僅用前一種呢?使用type 函式檢視,它們各自是str物件和unicode物件。這兩個物件有什麼差別嗎?還有經經常使用到的encode 和decode 又是幹什麼的呢?都說pyt...