小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

淺談 Python 2 中的編碼問(wèn)題

 編程教室 2021-03-18

Python 2.x 里的編碼實(shí)在是一件令人煩躁的事情。不斷有初學(xué)者被此問(wèn)題搞得暈頭轉(zhuǎn)向。我自己也在很長(zhǎng)一段時(shí)間內(nèi)深受其害,直到現(xiàn)在也仍會(huì)在開(kāi)發(fā)中偶爾被坑。在本教室的提問(wèn)和討論中,編碼問(wèn)題也占據(jù)了相當(dāng)大的比重。

然而這個(gè)問(wèn)題并不能一兩句話輕易解答。今天在這里稍微分析一下,希望能幫各位理清這里面的問(wèn)題。

要弄清編碼問(wèn)題,首先明確幾個(gè)概念:

str、unicode、encode、decode

str

就是我們通常說(shuō)的字符串,在 python 中是由引號(hào)包圍的一串字符。但是 Python 中的默認(rèn)字符并不包括中文及其他復(fù)雜字符(其他非英語(yǔ)語(yǔ)言、特殊符號(hào)等)。雖然你可以定義"你好"這樣的字符串,但在 Python Shell 中輸入一下你就會(huì)發(fā)現(xiàn):

>>> '你好'

'\xe4\xbd\xa0\xe5\xa5\xbd'>>>

在程序中,這兩個(gè)字符是被其他的一些按照某種格式的普通字符所表示。進(jìn)一步地,輸入:

>>> len('你好')

6

字符串的長(zhǎng)度也并不是想象中的2。

這就是我們一直說(shuō)的編碼。即通過(guò)某種規(guī)定的形式,用一些字符表示另一些字符。目的就是為了用少量的簡(jiǎn)單字符表示更多更復(fù)雜的字符。

上述的結(jié)果,是因?yàn)槲业?Python Shell 里默認(rèn)使用 UTF-8 對(duì)字符進(jìn)行了編碼。如果你在 Windows 下進(jìn)行嘗試,會(huì)是不一樣的結(jié)果,因?yàn)?Windows 默認(rèn)使用的是一種叫做 cp936 的編碼。

當(dāng)你需要通過(guò) Python 得到某些輸入或者輸出,比如讀取網(wǎng)頁(yè),輸出到控制臺(tái),讀寫(xiě)文件等等,需要處理的都是 str 類(lèi)型。所以必然逃不過(guò)編碼的問(wèn)題。

unicode

為了處理不同編碼的字符,于是有了 unicode。unicode 本身是一種編碼,因?yàn)樽銐虻拈L(zhǎng)度,它可以包容各種文字和符號(hào)。同時(shí)它也是 Python 中的一種類(lèi)型。在表示形式上,是字符串的引號(hào)前加上一個(gè) u。比如

>>> u'你好'

u'\u4f60\u597d'

>>> type(u'你好')

<type 'unicode'>

>>> type('你好')

<type 'str'>

可以看出,unicode 和 str 是兩種不同的類(lèi)型。

雖然 unicode 很強(qiáng)大,但在 Python 2 中,它不能被直接輸出,而必須通過(guò)某種編碼轉(zhuǎn)成 str。

encode & decode

encode 是 unicode 的一種方法,作用是按照某種形式對(duì)其進(jìn)行編碼,轉(zhuǎn)為 str。如:

>>> u'你好'.encode('utf-8')

'\xe4\xbd\xa0\xe5\xa5\xbd'

decode 是 str 的一種方法,作用是按照某種形式對(duì)其進(jìn)行解碼,轉(zhuǎn)為 unicode。如:

>>> '你好'.decode('utf-8')

u'\u4f60\u597d'

對(duì) unicode 進(jìn)行 encode 沒(méi)太大問(wèn)題,但對(duì) str decode 時(shí),因?yàn)?str 本身是有某種編碼的,這時(shí)候如果指定的編碼不符,就會(huì)產(chǎn)生討厭的亂碼:

>>> '你好'.decode('cp936')

u'\u6d63\u72b2\u30bd'

>>> print '你好'.decode('cp936')

浣犲ソ

在默認(rèn)的 utf-8 編碼環(huán)境下強(qiáng)行使用 cp936 編碼,就會(huì)出現(xiàn)亂碼。

小結(jié)一下就是:

輸入 -> str -> decode -> unicode -> encode -> str -> 輸出

那么通常問(wèn)題出在哪里呢?

一般情況下,我們?cè)诔绦蚶镒龅闹皇?/p>

輸入 -> str -> 邏輯處理 -> str -> 輸出

但在輸入輸出過(guò)程和中間的邏輯處理時(shí),很可能 Python 幫我們默認(rèn)做了一些 encode 和 decode 的工作。比如說(shuō),print 會(huì)按照環(huán)境的默認(rèn)形式進(jìn)行編碼,當(dāng)在需要 unicode 類(lèi)型的操作而程序拿到的是一個(gè) str 類(lèi)型是,會(huì)使用 ascii 進(jìn)行解碼。前者將可能導(dǎo)致亂碼顯示,而后者就直接報(bào)錯(cuò)。

舉兩個(gè)例子:

1

程序從網(wǎng)上抓取一段網(wǎng)頁(yè),中間的文字是 gbk 編碼,如 '\xbb\xb6\xd3\xad'(歡迎)。但抓取下來(lái),從默認(rèn) utf-8 控制臺(tái)輸出時(shí),就變成了 ???。同理存在于,Windows 下抓取了 utf-8 編碼的網(wǎng)頁(yè)。正確的處理方法是手動(dòng)做一次解碼:

>>> s = '\xbb\xb6\xd3\xad'

>>> print s

???

>>> s.decode('gbk')

u'\u6b22\u8fce'

>>> print s.decode('gbk')

歡迎

2

程序有一段從輸入得到的 cp936 編碼文字,如 '\xd5\xc5\xc8\xfd'(張三),和從數(shù)據(jù)庫(kù)取出的 unicode 字符串,如 u'\u597d\u4eba'(好人),兩者需要做拼接時(shí):

>>> a = '\xd5\xc5\xc8\xfd'

>>> b = u'好人'

>>> a + b

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

UnicodeDecodeError: 'ascii' codec can't decode byte 0xd5 in position 0: ordinal not in range(128)

拋出了經(jīng)常發(fā)生的 UnicodeDecodeError 異常。這是因?yàn)樵?str 和 unicode 做 + 操作時(shí),會(huì)自動(dòng)將 str 轉(zhuǎn)成 unicode,并且使用了 ascii 編碼。同樣的問(wèn)題也會(huì)發(fā)生在對(duì)一個(gè) str 對(duì)象直接使用 encode 的時(shí)候。比如:

>>> a = '\xd5\xc5\xc8\xfd'

>>> a.encode('utf-8')

原因也是一樣,encode 是 unicode 類(lèi)型的方法,對(duì) str 進(jìn)行調(diào)用時(shí),程序會(huì)默認(rèn)先直接試圖用 ascii 編碼把 str 轉(zhuǎn)成 unicode。

正確的做法:

>>> a.decode('cp936') + b

u'\u5f20\u4e09\u597d\u4eba'

>>> a.decode('cp936').encode('utf-8')

'\xe5\xbc\xa0\xe4\xb8\x89'

另外還有個(gè)要注意的地方是,Python 代碼的 py 文件默認(rèn)是是用 ascii 編碼,所以在程序里有中文的時(shí)候,需要在文件開(kāi)頭指定編碼,例如:

# coding: utf-8

有些 IDE 比如 PyScripter 會(huì)另外設(shè)置你的文件編碼,有時(shí)還會(huì)有沖突。

要注意搞清:

程序文件本身的編碼 - 你在程序里賦值的字符串

輸入來(lái)源的編碼 - 獲取的變量值

輸出環(huán)境的編碼 - 控制臺(tái)、文件、網(wǎng)頁(yè)

最好能保證這幾個(gè)的一致性,不一致時(shí)也要做好相應(yīng)的轉(zhuǎn)換,才能避免掉進(jìn)編碼的坑。

最后,為巴黎恐怖襲擊中的遇難者以及所有戰(zhàn)爭(zhēng)的受害者哀悼。本教室有不少身處國(guó)外的讀者,各位注意自身安全。愿大家都平安。

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多