更新時(shí)間:2018-11-26 來(lái)源:黑馬程序員 瀏覽量:
1. 字符與字節(jié)
一個(gè)字符不等價(jià)于一個(gè)字節(jié),字符是人類(lèi)能夠識(shí)別的符號(hào),而這些符號(hào)要保存到計(jì)算的存儲(chǔ)中就需要用計(jì)算機(jī)能夠識(shí)別的字節(jié)來(lái)表示。一個(gè)字符往往有多種表示方法,不同的表示方法會(huì)使用不同的字節(jié)數(shù)。比如字母A-Z都可以用ASCII碼表示(占用一個(gè)字節(jié)),也可以用UNICODE表示(占兩個(gè)字節(jié)),還可以用UTF-8表示(占用一個(gè)字節(jié))。字符編碼的作用就是將人類(lèi)可識(shí)別的字符轉(zhuǎn)換為機(jī)器可識(shí)別的字節(jié)碼,以及反向過(guò)程。
UNICDOE才是真正的字符串,而用ASCII、UTF-8、GBK等字符編碼表示的是字節(jié)串。
我們寫(xiě)代碼是寫(xiě)在文件中的,而字符是以字節(jié)形式保存在文件中的,因此當(dāng)我們?cè)谖募卸x個(gè)字符串時(shí)被當(dāng)做字節(jié)串也是可以理解的。但是,我們需要的是字符串,而不是字節(jié)串。Python2把字節(jié)串當(dāng)做字符串來(lái)使用。最能說(shuō)明這個(gè)問(wèn)題的操作就是取一個(gè)包含中文字符的字符串的長(zhǎng)度:
對(duì)字符串取長(zhǎng)度,結(jié)果應(yīng)該是所有字符串的個(gè)數(shù),無(wú)論中文還是英文
對(duì)字符串對(duì)應(yīng)的字節(jié)串取長(zhǎng)度,就跟編碼(encode)過(guò)程使用的字符編碼有關(guān)了(比如:UTF-8編碼,一個(gè)中文字符需要用3個(gè)字節(jié)來(lái)表示;GBK編碼,一個(gè)中文字符需要2個(gè)字節(jié)來(lái)表示)
注意:Windows的cmd終端字符編碼默認(rèn)為GBK,因此在cmd輸入的中文字符需要用兩個(gè)字節(jié)表示
>>> # Python2
>>> a = 'Hello,中國(guó)' # 字節(jié)串,長(zhǎng)度為字節(jié)個(gè)數(shù) = len('Hello,')+len('中國(guó)') = 6+2*2 = 10
>>> b = u'Hello,中國(guó)' # 字符串,長(zhǎng)度為字符個(gè)數(shù) = len('Hello,')+len('中國(guó)') = 6+2 = 8
>>> c = unicode(a, 'gbk') # 其實(shí)b的定義方式是c定義方式的簡(jiǎn)寫(xiě),都是將一個(gè)GBK編碼的字節(jié)串解碼(decode)為一個(gè)Uniocde字符串
>>>
>>> print(type(a), len(a))
(, 10)
>>> print(type(b), len(b))
(, 8)
>>> print(type(c), len(c))
(, 8)
2. 編碼與解碼
編碼(encode):將Unicode字符串(中的代碼點(diǎn))轉(zhuǎn)換特定字符編碼對(duì)應(yīng)的字節(jié)串的過(guò)程和規(guī)則
解碼(decode):將特定字符編碼的字節(jié)串轉(zhuǎn)換為對(duì)應(yīng)的Unicode字符串(中的代碼點(diǎn))的過(guò)程和規(guī)則
可見(jiàn),無(wú)論是編碼還是解碼,都需要一個(gè)重要因素,就是特定的字符編碼。因?yàn)橐粋€(gè)字符用不同的字符編碼進(jìn)行編碼后的字節(jié)值以及字節(jié)個(gè)數(shù)大部分情況下是不同的,反之亦然。
3、Python中的默認(rèn)編碼
Python2和Python3的解釋器使用的默認(rèn)編碼是不一樣的,我們可以通過(guò)sys.getdefaultencoding()來(lái)獲取默認(rèn)編碼:
>>> # Python2
>>> import sys
>>> sys.getdefaultencoding()
'ascii'
>>> # Python3
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'
因此,對(duì)于Python2來(lái)講,Python解釋器在讀取到中文字符的字節(jié)碼嘗試解碼操作時(shí),會(huì)先查看當(dāng)前代碼文件頭部是否有指明當(dāng)前代碼文件中保存的字節(jié)碼對(duì)應(yīng)的字符編碼是什么。如果沒(méi)有指定則使用默認(rèn)字符編碼"ASCII"進(jìn)行解碼導(dǎo)致解碼失敗,導(dǎo)致如下錯(cuò)誤:
SyntaxError: Non-ASCII character '\xc4' in file xxx.py on line 11, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
對(duì)于Python3來(lái)講,執(zhí)行過(guò)程是一樣的,只是Python3的解釋器以"UTF-8"作為默認(rèn)編碼,但是這并不表示可以完全兼容中文問(wèn)題。比如我們?cè)赪indows上進(jìn)行開(kāi)發(fā)時(shí),Python工程及代碼文件都使用的是默認(rèn)的GBK編碼,也就是說(shuō)Python代碼文件是被轉(zhuǎn)換成GBK格式的字節(jié)碼保存到磁盤(pán)中的。Python3的解釋器執(zhí)行該代碼文件時(shí),試圖用UTF-8進(jìn)行解碼操作時(shí),同樣會(huì)解碼失敗,導(dǎo)致如下錯(cuò)誤:
SyntaxError: Non-UTF-8 code starting with '\xc4' in file xxx.py on line 11, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
創(chuàng)建一個(gè)工程之后先確認(rèn)該工程的字符編碼是否已經(jīng)設(shè)置為UTF-8
為了兼容Python2和Python3,在代碼頭部聲明字符編碼:-*- coding:utf-8 -*-
4、Python2與Python3編碼過(guò)程
Python2中的字符串進(jìn)行字符編碼轉(zhuǎn)換過(guò)程是:
字節(jié)串-->decode('原來(lái)的字符編碼')-->Unicode字符串-->encode('新的字符編碼')-->字節(jié)串
Python3中定義的字符串默認(rèn)就是unicode,因此不需要先解碼,可以直接編碼成新的字符編碼:
字符串-->encode('新的字符編碼')-->字節(jié)串
作者:傳智播人工智能+Python培訓(xùn)學(xué)院
首發(fā): http://python.itheima.com