精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

不想再被鄙視?那就看進(jìn)來! 一文搞懂Python 2字符編碼

開發(fā) 后端
本文的目標(biāo)是解釋清楚 python2.7 中unicode、str的編解碼關(guān)系,力求在鄙視鏈中前進(jìn)一步。本文實(shí)驗(yàn)主要基于win7,Python2.7;以及Linux ,Python2.7。

程序員都自視清高,覺得自己是創(chuàng)造者,經(jīng)常鄙視不太懂技術(shù)的產(chǎn)品或者QA。可悲的是,程序員之間也相互鄙視,程序員的鄙視鏈流傳甚廣,作為一個(gè)Python程序員,自然最關(guān)心的是下面這幅圖啦

我們項(xiàng)目組一值使用Python2.7,雖然我們也知道Python3的諸多好處,也曾經(jīng)蠢蠢欲動(dòng)過,但由于各種歷史原因,以及業(yè)務(wù)的壓力,我們只可能繼續(xù)使用Python2.7。更悲哀的是,我們組不是那么international,所以代碼中還是涉及到大量的中文,因此偶爾也會(huì)遇到亂碼以及UnicodeError,于是生活在了鄙視鏈的末端。

因此,本文的目標(biāo)是解釋清楚 python2.7 中unicode、str的編解碼關(guān)系,力求在鄙視鏈中前進(jìn)一步。

注意:本文實(shí)驗(yàn)主要基于win7,Python2.7;以及Linux ,Python2.7。除非特殊說明,所有的命令都是在終端中交互式輸入;如果沒有強(qiáng)調(diào)平臺(tái),那么就是window上的結(jié)果。下面是一些默認(rèn)的環(huán)境信息(其重要性后文會(huì)介紹)

windows

  1. >>> import sys,locale 
  2. >>> sys.getdefaultencoding() 
  3. 'ascii' 
  4. >>> locale.getdefaultlocale() 
  5. ('zh_CN''cp936'
  6. >>> sys.stdin.encoding 
  7. 'cp936' 
  8. >>> sys.stdout.encoding 
  9. 'cp936' 
  10. >>> sys.getfilesystemencoding() 
  11. 'mbcs' 

注意,上面CP936是GBK的別名,在https://docs.python.org/2/library/codecs.html#standard-encodings 可以查看。

Linux

  1. >>> import sys,locale 
  2.  
  3. >>> sys.getdefaultencoding() 
  4.  
  5. 'ascii' 
  6.  
  7. >>> locale.getdefaultlocale() 
  8.  
  9. ('zh_CN''UTF-8'
  10.  
  11. >>> sys.stdin.encoding 
  12.  
  13. 'UTF-8' 
  14.  
  15. >>> sys.stdout.encoding 
  16.  
  17. 'UTF-8' 
  18.  
  19. >>> sys.getfilesystemencoding() 
  20.  
  21. 'UTF-8' 

從字符編碼說起

首先來說一說gbk gb2312 unicode utf-8這些術(shù)語,這些術(shù)語與語言無關(guān)。

計(jì)算機(jī)的世界只有0和1,因此任何字符(也就是實(shí)際的文字符號(hào))也是由01串組成。計(jì)算機(jī)為了運(yùn)算方便,都是8個(gè)bit組成一個(gè)字節(jié)(Byte),字符表達(dá)的最小單位就是字節(jié),即一個(gè)字符占用一個(gè)或者多個(gè)字節(jié)。字符編碼(character encoding)就是字集碼,編碼就是將字符集中的字符映射為一個(gè)唯一二進(jìn)制的過程。

計(jì)算機(jī)發(fā)源于美國,使用的是英文字母(字符),所有26個(gè)字母的大小寫加上數(shù)字0到10,加上符號(hào)和控制字符,總數(shù)也不多,用一個(gè)字節(jié)(8個(gè)bit)就能表示所有的字符,這就是ANSI的“Ascii”編碼(American Standard Code for Information Interchange,美國信息互換標(biāo)準(zhǔn)代碼)。比如,小寫字母‘a’的ascii 碼是01100001,換算成十進(jìn)制就是97,十六進(jìn)制就是0x61。計(jì)算機(jī)中,一般都是用十六進(jìn)制來描述字符編碼。

但是當(dāng)計(jì)算機(jī)傳到中國的時(shí)候,ASCII編碼就行不通了,漢字這么多,一個(gè)字節(jié)肯定表示不下啊,于是有了GB 2312(中國國家標(biāo)準(zhǔn)簡體中文字符集)。GB2312使用兩個(gè)字節(jié)來對(duì)一個(gè)字符進(jìn)行編碼,其中前面的一個(gè)字節(jié)(稱之為高字節(jié))從0xA1用到 0xF7,后面一個(gè)字節(jié)(低字節(jié))從0xA1到0xFE,GB2312能表示幾千個(gè)漢字,而且與asill嗎也是兼容的。

但后來發(fā)現(xiàn),GB2312還是不夠用,于是進(jìn)行擴(kuò)展,產(chǎn)生了GBK(即漢字內(nèi)碼擴(kuò)展規(guī)范), GBK同Gb2312一樣,兩個(gè)字節(jié)表示一個(gè)字符,但區(qū)別在于,放寬了對(duì)低字節(jié)的要求,因此能表示的范圍擴(kuò)大到了20000多。后來,為了容納少數(shù)名族,以及其他漢字國家的文字,出現(xiàn)了GB13080。GB13080是兼容GBK與GB2312的,能容納更多的字符,與GBK與GB2312不同的是,GB18030采用單字節(jié)、雙字節(jié)和四字節(jié)三種方式對(duì)字符編碼

因此,就我們關(guān)心的漢字而言,三種編碼方式的表示范圍是:

GB18030 》 GBK 》 GB2312

GBK是GB2312的超集,GB1803又是GBK的超集。后面也會(huì)看到,一個(gè)漢字可以用GBK表示,但不一定能被GB2312所表示

當(dāng)然,世界上還有更多的語言與文字,每種文字都有自己的一套編碼規(guī)則,這樣一旦跨國就會(huì)出現(xiàn)亂碼,亟待一個(gè)全球統(tǒng)一的解決辦法。這個(gè)時(shí)候ISO(國際標(biāo)準(zhǔn)化組織)出馬了,發(fā)明了”Universal Multiple-Octet Coded Character Set”,簡稱 UCS, 俗稱 “unicode”。目標(biāo)很簡單:廢了所有的地區(qū)性編碼方案,重新搞一個(gè)包括了地球上所有文化、所有字母和符號(hào) 的編碼!

unicode每種語言中的每個(gè)字符設(shè)定了統(tǒng)一并且唯一的二進(jìn)制編碼,以滿足跨語言、跨平臺(tái)進(jìn)行文本轉(zhuǎn)換、處理的要求。unicode編碼一定以u(píng)開頭。

但是,unicode只是一個(gè)編碼規(guī)范,是所有字符對(duì)應(yīng)二進(jìn)制的集合,而不是具體的編碼規(guī)則。或者說,unicode是表現(xiàn)形式,而不是存儲(chǔ)形式,就是說沒用定義每個(gè)字符是如何以二進(jìn)制的形式存儲(chǔ)的。這個(gè)就跟GBK這些不一樣,GBK是表里如下,表現(xiàn)形式即存儲(chǔ)形式。

比如漢字“嚴(yán)”的unicode編碼是u4e25,對(duì)應(yīng)的二進(jìn)制是1001110 00100101,但是當(dāng)其經(jīng)過網(wǎng)絡(luò)傳輸或者文件存儲(chǔ)時(shí),是沒法知道怎么解析這些二進(jìn)制的,容易和其他字節(jié)混在一起。那么怎么存儲(chǔ)unicode呢,于是出現(xiàn)了UTF(UCS Transfer Format),這個(gè)是具體的編碼規(guī)則,即UTF的表現(xiàn)形式與存儲(chǔ)格式是一樣的。

因此,可以說,GBK和UTF-8是同一個(gè)層面的東西,跟unicode是另一個(gè)層面的東西,unicode飄在空中,如果要落地,需要轉(zhuǎn)換成utf-8或者GBK。只不過,轉(zhuǎn)換成Utf-8,大家都能懂,更懂用,而轉(zhuǎn)換成GBK,只有中國人才看得懂

UTF也有不同的實(shí)現(xiàn),如UTF-8, UTF-16, 這里以UTF-8為例進(jìn)行講解(下面一小節(jié)引用了阮一峰的文章)。

unicode與utf-8

UTF-8***的一個(gè)特點(diǎn),就是它是一種變長的編碼方式。它可以使用1~4個(gè)字節(jié)表示一個(gè)符號(hào),根據(jù)不同的符號(hào)而變化字節(jié)長度。UTF-8的編碼規(guī)則很簡單,只有二條:

1)對(duì)于單字節(jié)的符號(hào),字節(jié)的***位設(shè)為0,后面7位為這個(gè)符號(hào)的unicode碼。因此對(duì)于英語字母,UTF-8編碼和ASCII碼是相同的。

2)對(duì)于n字節(jié)的符號(hào)(n>1),***個(gè)字節(jié)的前n位都設(shè)為1,第n+1位設(shè)為0,后面字節(jié)的前兩位一律設(shè)為10。剩下的沒有提及的二進(jìn)制位,全部為這個(gè)符號(hào)的unicode碼。

下表總結(jié)了編碼規(guī)則,字母x表示可用編碼的位。

  1. Unicode符號(hào)范圍      |        UTF-8編碼方式 
  2. (十六進(jìn)制)           |        (二進(jìn)制) 
  3. ----------------------+--------------------------------------------- 
  4. 0000 0000-0000 007F | 0xxxxxxx 
  5. 0000 0080-0000 07FF | 110xxxxx 10xxxxxx 
  6. 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 
  7. 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 

以漢字“嚴(yán)”為例,演示如何實(shí)現(xiàn)UTF-8編碼。

已知“嚴(yán)”的unicode是4E25(100111000100101),根據(jù)上表,可以發(fā)現(xiàn)4E25處在第三行的范圍內(nèi)(0000 0800-0000 FFFF),因此“嚴(yán)”的UTF-8編碼需要三個(gè)字節(jié),即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,從“嚴(yán)”的***一個(gè)二進(jìn)制位開始,依次從后向前填入格式中的x,多出的位補(bǔ)0。這樣就得到了,“嚴(yán)”的UTF-8編碼是“11100100 10111000 10100101”,轉(zhuǎn)換成十六進(jìn)制就是E4B8A5。

當(dāng)編解碼遇上Python2.x

下面使用Python語言來驗(yàn)證上面的理論。在這一章節(jié)中,當(dāng)提到unicode,一般是指unicode type,即Python中的類型;也會(huì)提到unicode編碼、unicode函數(shù),請(qǐng)大家注意區(qū)別。

另外,對(duì)于編碼,也有兩種意思。***個(gè)是名字,指的是字符的二進(jìn)制表示,如unicode編碼、gbk編碼。第二個(gè)是動(dòng)詞,指的是從字符到二進(jìn)制的映射過程。不過后文中,編碼作為動(dòng)詞,狹義理解為從unicode類型轉(zhuǎn)換成str類型的過程,解碼則是相反的過程。另外強(qiáng)調(diào)的是,unicode類型一定是unicode編碼,而str類型可能是gbk、ascii或者utf-8編碼。

unicode 與 str 區(qū)別

在python2.7中,有兩種“字符串”類型,分別是str 與 unicode,他們有同一個(gè)基類basestring。str是plain string,其實(shí)應(yīng)該稱之為字節(jié)串,因?yàn)槭敲恳粋€(gè)字節(jié)換一個(gè)單位長度。而unicode就是unicode string,這才是真正的字符串,一個(gè)字符(可能多個(gè)字節(jié))算一個(gè)單位長度。

python2.7中,unicode類型需要在文本之間加u表示。

  1. >>> us = u'嚴(yán)' 
  2.  
  3. >>> print type(us), len(us) 
  4.  
  5. <type 'unicode'> 1 
  6.  
  7. >>> s = '嚴(yán)' 
  8.  
  9. >>> print type(s), len(s) 
  10.  
  11. <type 'str'> 2 
  12.  
  13. >>> 

從上可以看到,***,us、s的類型是不一樣的;其二,同一個(gè)漢字,不同的類型其長度也是不一樣的,對(duì)于unicode類型的實(shí)例,其長度一定是字符的個(gè)數(shù),而對(duì)于str類型的實(shí)例,其長度是字符對(duì)應(yīng)的字節(jié)數(shù)目。這里強(qiáng)調(diào)一下,s(s = ‘嚴(yán)’)的長度在不同的環(huán)境下是不一樣的!后文會(huì)解釋

__str__ __repr__的區(qū)別

這是python中兩個(gè)magic method,很容易讓新手迷糊,因?yàn)楹芏鄷r(shí)候,二者的實(shí)現(xiàn)是一樣的,但是這兩個(gè)函數(shù)是用在不同的地方

_str__, 主要是用于展示,str(obj)或者print obj的時(shí)候調(diào)用,返回值一定是一個(gè)str 對(duì)象

__repr__, 是被repr(obj), 或者在終端直接打obj的時(shí)候調(diào)用

  1. >>> us = u'嚴(yán)' 
  2.  
  3. >>> us 
  4.  
  5. u'\u4e25' 
  6.  
  7. >>> print us 
  8.  
  9. 嚴(yán) 

可以看到,不使用print返回的是一個(gè)更能反映對(duì)象本質(zhì)的結(jié)果,即us是一個(gè)unicode對(duì)象(最前面的u表示,以及unicode編碼是用的u),且“嚴(yán)”的unicode編碼確實(shí)是4E25。而print調(diào)用可us.__str__,等價(jià)于print str(us),使得結(jié)果對(duì)用戶更友好。那么unicode.__str__是怎么轉(zhuǎn)換成str的呢,答案會(huì)在后面揭曉

unicode str utf-8關(guān)系

前面已經(jīng)提到,unicode只是編碼規(guī)范(只是字符與二進(jìn)制的映射集合),而utf-8是具體的編碼規(guī)則(不僅包含字符與二進(jìn)制的映射集合,而且映射后的二進(jìn)制是可以用于存儲(chǔ)和傳輸?shù)模磚tf-8負(fù)責(zé)把unicode轉(zhuǎn)換成可存儲(chǔ)和傳輸?shù)亩M(jìn)制字符串即str類型,我們稱這個(gè)轉(zhuǎn)換過程為編碼。而從str類型到unicode類型的過程,我們稱之為解碼。

Python中使用decode()和encode()來進(jìn)行解碼和編碼,以u(píng)nicode類型作為中間類型。如下圖所示

  decode     encode

str ---------> unicode --------->str

即str類型調(diào)用decode方法轉(zhuǎn)換成unicode類型,unicode類型調(diào)用encode方法轉(zhuǎn)換成str類型。for example

  1. >>> us = u'嚴(yán)' 
  2.  
  3. >>> ss = us.encode('utf-8'
  4.  
  5. >>> ss 
  6.  
  7. '\xe4\xb8\xa5' 
  8.  
  9. >>> type(ss) 
  10.  
  11. <type 'str'
  12.  
  13. >>> ss.decode('utf-8') == us 
  14.  
  15. True 

從上可以看出encode與decode兩個(gè)函數(shù)的作用,也可以看出’嚴(yán)’的utf8編碼是E4B8A5。

就是說我們使用unicode.encode將unicode類型轉(zhuǎn)換成了str類型,在上面也提到unicode.__str__也是將unicode類型轉(zhuǎn)換成str類型。二者有什么卻比呢

unicode.encode 與 unicode.__str__的區(qū)別

首先看看文檔

 

  1. str.encode([encoding[, errors]]) 
  2.  
  3.   Return an encoded version of the string. Default encoding is the current default string encoding.  
  4.    
  5.  
  6. object.__str__(self) 
  7.  
  8.   Called by the str() built-in function and by the print statement to compute the “informal” string representation of an object. 

注意:str.encode 這里的str是basestring,是str類型與unicode類型的基類

可以看到encode方法是有可選的參數(shù):encoding 和 errors,在上面的例子中encoding即為utf-8;而__str__是沒有參數(shù)的,我們可以猜想,對(duì)于unicode類型,__str__函數(shù)一定也是使用了某種encoding來對(duì)unicode進(jìn)行編碼。

首先不禁要問,如果encode方法沒有帶入?yún)?shù),是什么樣子的:

  1. >>> us.encode() 
  2.  
  3. Traceback (most recent call last): 
  4.  
  5. File "<stdin>", line 1, in <module> 
  6.  
  7. UnicodeEncodeError: 'ascii' codec can't encode character u'\u4e25' in position 0: ordinal not in range(128) 

不難看出,默認(rèn)使用的就是ascii碼來對(duì)unicode就行編碼,為什么是ascii碼,其實(shí)就是系統(tǒng)默認(rèn)編碼(sys.getdefaultencoding的返回值)。ascii碼顯然無法表示漢字,于是拋出了異常。而使用utf-8編碼的時(shí)候,由于utf能夠表示這個(gè)漢字,所以沒報(bào)錯(cuò)。

如果直接打印ss(us.encode(‘utf-8’)的返回值)會(huì)怎么樣

  1. >>> print ss 
  2.  
  3. 涓 

結(jié)果略有些奇怪,us.__str__(即直接打印us)的結(jié)果不一樣,那么試試encoding = gbk呢?

  1. >>> print us.encode('gbk'
  2.  
  3. 嚴(yán) 

U got it! 事實(shí)上也是如此,python會(huì)采用終端默認(rèn)的編碼(用locale.getdefaultlocale()查看,windows是為gbk)將unicode編碼成str類型。

在Linux(終端編碼為utf-8),結(jié)果如下:

  1. >>> us= u'嚴(yán)' 
  2.  
  3. >>> print us.encode('utf-8'
  4.  
  5. 嚴(yán) 
  6.  
  7. >>> print us.encode('gbk'
  8.  
  9. ▒▒ 
  10.  
  11. >>> print us 
  12.  
  13. 嚴(yán) 
  14.  
  15. >>> 

注意上面的亂碼!

unicode gbk之間的轉(zhuǎn)換

在上上小節(jié),介紹了unicode可以通過utf-8編碼(encoding = utf-8),轉(zhuǎn)換成utf-8表示的str,在上一節(jié)也可以看出unicode也可以通過gbk編碼(encoding=gbk),轉(zhuǎn)換成gbk表示的str。這里有點(diǎn)暈,留作***個(gè)問題,后面解釋

unicode與utf8之間的相互轉(zhuǎn)換可以計(jì)算得知,但unicode與gbk之間的相互轉(zhuǎn)換沒有計(jì)算公式,就只能靠查表了,就是說有一張映射表,有某一個(gè)漢字對(duì)應(yīng)的unicode表示與gbk表示的映射關(guān)系

  1. >> us = u'嚴(yán)' 
  2.  
  3. >>> us 
  4.  
  5. u'\u4e25' 
  6.  
  7. >>> us.encode('gbk'
  8.  
  9. '\xd1\xcf' 
  10.  
  11. >>> us.encode('gb2312'
  12.  
  13. '\xd1\xcf' 
  14.  
  15. >>> us.encode('gb18030'
  16.  
  17. '\xd1\xcf' 
  18.  
  19. >>> s = '嚴(yán)' 
  20.  
  21. >>> s 
  22.  
  23. '\xd1\xcf' 
  24.  
  25. >>> 

從上不難看出,嚴(yán)的unicdoe編碼是4e25,GBK編碼是d1cf,因此us通過gbk編碼就是d1cf。同樣也能看到,GB18030,GBK,GB2312是兼容的

為什么print us.encode(‘utf-8’)打印出“涓”

ss = us.encode(‘utf-8’), ss是一個(gè)str類型,直接打印結(jié)果有點(diǎn)奇怪,一個(gè)“涓”字,那一個(gè)str類型的“涓”是哪些二進(jìn)制組成的呢

 

  1. >>> s = '涓' 
  2.  
  3. >>> s 
  4.  
  5. '\xe4\xb8' 

可以看到,str類型的“涓”,其二進(jìn)制是E4B8,跟’嚴(yán)’的utf8編碼(E4B8A5)相差了一個(gè)A5,那么就是因?yàn)锳5顯示不出來,驗(yàn)證如下:

  1. >>> print '--%s--' % ss 
  2.  
  3. --涓?- 

因此,只是碰巧顯示了“涓”而已,事實(shí)上ss跟“”涓“”毫無關(guān)系

回答***個(gè)問題:str類型到底是什么

在上上小節(jié),提到了utf-8編碼的str,與gbk編碼的str,感覺有點(diǎn)繞。我們知道,一個(gè)漢字‘嚴(yán)’,可存儲(chǔ)的編碼格式可以是gbk(’xd1xcf’),也可以是utf-8(’xe4xb8xa5’),那么當(dāng)我們?cè)诮K端敲入這個(gè)漢字的時(shí)候,是哪一種格式呢?取決于終端默認(rèn)編碼。

windows上(默認(rèn)終端編碼為gbk):

  1. >>> s = '嚴(yán)' 
  2.  
  3. >>> s 
  4.  
  5. '\xd1\xcf' 

Linux上(默認(rèn)終端編碼為utf-8):

  1. >>> a = '嚴(yán)' 
  2.  
  3. >>> a 
  4.  
  5. '\xe4\xb8\xa5' 

同樣一個(gè)漢字,同樣都是Python中的str類型,在不同的編碼格式下,其二進(jìn)制是不一樣的。因此,其長度也是不一樣的,對(duì)于str類型,其長度是對(duì)應(yīng)的字節(jié)長度。

也能看出gbk編碼的字節(jié)長度一般小于utf-8,這也是gbk繼續(xù)存在的一個(gè)原因。

這里,要強(qiáng)調(diào)一下,unicode的二進(jìn)制形式是與終端的編碼格式無關(guān)的!這個(gè)也不難理解。

unicode函數(shù)

str類型到unicode類型的轉(zhuǎn)換,出了上面提到的str.decode,還有一個(gè)unicode函數(shù)。兩個(gè)函數(shù)的簽名為:

  1. unicode(object[, encoding[, errors]]) 
  2.  
  3. Return the Unicode string version of object using one of the following modes:  
  4.  
  5. str.decode([encoding[, errors]]) 
  6.  
  7. Decodes the string using the codec registered for encoding. encoding defaults to the default string encoding. 

二者參數(shù)相同,事實(shí)上二者是等價(jià)的,encoding的默認(rèn)值也是一樣的,都是sys.getdefaultencoding()的結(jié)果。for example:

 

  1. unicode(object[, encoding[, errors]]) 
  2.  
  3. Return the Unicode string version of object using one of the following modes:  
  4.  
  5. str.decode([encoding[, errors]]) 
  6.  
  7. Decodes the string using the codec registered for encoding. encoding defaults to the default string encoding. 

***個(gè)UnicodeDecodeError,就是因?yàn)橄到y(tǒng)默認(rèn)的編碼是asill嗎;第二個(gè)UnicodeDecodeError,是因?yàn)椋瑂(str類型的實(shí)例)的編碼取決于終端默認(rèn)編碼(即windows下的gbk),為了能打印出來,也就必須用gbk編碼來表示這個(gè)str,因此只能查詢gbk與unicode的映射表將s轉(zhuǎn)換成unicode類型。

為啥調(diào)用sys.setdefaultencoding

在諸多Python代碼中,都會(huì)看到這么一段:

  1. import sys 
  2.  
  3. reload(sys) 
  4.  
  5. sys.setdefaultencoding('utf-8'

不難猜想,setdefaultencoding跟getdefaultencoding是配對(duì)的,為啥要將系統(tǒng)的默認(rèn)編碼設(shè)置成utf-8,其實(shí)就是解決str到unicode的轉(zhuǎn)換問題。

上一小節(jié)已經(jīng)提到過,使用unicode函數(shù)將str類型轉(zhuǎn)換成unicode類型時(shí),要考慮兩個(gè)因素:***,str本身是什么編碼的;第二,如果沒有傳入encoding參數(shù),默認(rèn)使用sys.getdefaultencoding。encoding參數(shù)必須與str本身的編碼對(duì)應(yīng),否則就是UnicodeDecodeError。

寫python代碼的程序都知道,我們要在py文件***行寫上:

  1. # -*- coding: utf-8 -*- 

這句話的作用在于,告訴編輯器,該文件里面的所有str都采用utf-8編碼,且存儲(chǔ)文件的時(shí)候也是使用utf-8格式。

然后文件中就會(huì)使用下面的這種代碼。

  1. s='中文' 
  2.  
  3. us=unicode(s) 

使用unicode強(qiáng)制轉(zhuǎn)換的時(shí)候,都不習(xí)慣帶參數(shù),為了保證encoding參數(shù)必須與str本身的編碼一致,所以使用setdefaultencoding將系統(tǒng)默認(rèn)編碼設(shè)置為utf-8

亂碼與UnicodeError

下面介紹幾種常見的亂碼與異常UnicodeError, 大多數(shù)亂碼或者異常的原因在前面已經(jīng)講過了,同時(shí),對(duì)于一些亂碼,也試圖給出可行的解決辦法。

UnicodeError包括UnicodeDecodeError 與UnicodeEncodeError ,前者是decode也就是str轉(zhuǎn)unicode的時(shí)候出了異常,后者則是encode也就是unicode轉(zhuǎn)str的時(shí)候出了異常。

對(duì)于一個(gè)str,直接打印

例子就是上面反復(fù)提到的例子

  1. >>> ss = us.encode('utf-8'
  2.  
  3. >>> print ss 
  4.  
  5. 涓 

如果一個(gè)str類型來自網(wǎng)絡(luò)或者文件讀取,***先按照對(duì)端encode的方式先decode成unicode,然后再輸出(輸出的時(shí)候會(huì)自動(dòng)轉(zhuǎn)換成期望終端支持的編碼格式的str)

編碼范圍無法包括的漢字

直接上例子

  1. >>> newus = u'囍' 
  2.  
  3. >>> newus 
  4.  
  5. u'\u56cd' 
  6.  
  7. >>> newus.encode('gbk'
  8.  
  9. '\x87\xd6' 
  10.  
  11. >>> newus.encode('gb2312'
  12.  
  13. Traceback (most recent call last): 
  14.  
  15. File "<stdin>", line 1, in <module> 
  16.  
  17. UnicodeEncodeError: 'gb2312' codec can't encode character u'\u56cd' in position 0: illegal multibyte sequence 
  18.  
  19. >>> 

可以看到,‘囍’字可以被gbk編碼,但是不能被gb2312編碼。

str轉(zhuǎn)unicode的時(shí)候

在上面講unicode函數(shù)的時(shí)候已經(jīng)舉過例子,會(huì)爆出UnicodeDecodeError 異常。

這個(gè)錯(cuò)誤比較的原因,更多來自str到unicode的默認(rèn)轉(zhuǎn)換,比如一個(gè)str與一個(gè)unicode相加的時(shí)候:

  1. >>> a = '嚴(yán)' 
  2.  
  3. >>> b = u'嚴(yán)' 
  4.  
  5. >>> c = a + b 
  6.  
  7. Traceback (most recent call last): 
  8.  
  9. File "<stdin>", line 1, in <module> 
  10.  
  11. UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 0: ordinal not in range(128) 

unicode 與 str相加,str會(huì)轉(zhuǎn)換為unicode,使用默認(rèn)的unicode(strobj, encoding = sys.getdefaultencoding())

看起來向unicode編碼的字符串

某些情況下,我們打印出一個(gè)str類型,看到結(jié)果是’\u4e25’, 或者’u4e25’,對(duì)于這個(gè)字符串,是不是很眼熟,不錯(cuò), ‘嚴(yán)‘的unicode編碼就是u’u4e25’。仔細(xì)一看,只是在引號(hào)前面多了一個(gè)u(表示是一個(gè)unicode類型)。那么當(dāng)我們看到一個(gè)’u4e25’的時(shí)候,怎么知道對(duì)應(yīng)的漢字是什么?對(duì)于已知的這種格式的str,自然可以手動(dòng)加一個(gè)u,然后在終端輸出,但是如果是一個(gè)變量,需要自動(dòng)轉(zhuǎn)換成unicode呢,這個(gè)時(shí)候就可以使用python-specific-encodings中的unicode_escape

  1. >>> s = '\u4e25' 
  2.  
  3. >>> s 
  4.  
  5. '\\u4e25' 
  6.  
  7. >>> us = s.decode('unicode_escape'
  8.  
  9. >>> us 
  10.  
  11. u'\u4e25' 

十六進(jìn)制格式的字符串

有時(shí)候,也會(huì)看到類似這樣的str,’\xd1\xcf’, 看起來也很熟悉,跟漢字“嚴(yán)”的gbk編碼’xd1xcf’很像,區(qū)別在于前者多了一個(gè)‘’, 這樣就無法解釋成一個(gè)十六進(jìn)制了。解決辦法是python-specific-encodings中的string_escape

  1. >>> s='\\xd1\\xcf' 
  2.  
  3. >>> s 
  4.  
  5. '\\xd1\\xcf' 
  6.  
  7. >>> print s 
  8.  
  9. \xd1\xcf 
  10.  
  11. >>> news = s.decode('string_escape'
  12.  
  13. >>> news 
  14.  
  15. '\xd1\xcf' 
  16.  
  17. >>> print news 
  18.  
  19. 嚴(yán) 

 

給讀者的一個(gè)問題

在這里留下一個(gè)問題:

  1. u'嚴(yán)' == '嚴(yán)' 

返回值是True 還是 False呢?當(dāng)然這里故意省去了上下文環(huán)境,不過明確的說,在不同的編碼環(huán)境下,答案是不一樣的,原因都在上文中!

總結(jié)與建議

不管怎么樣解釋,python2.x中的字符編碼還是一件讓人頭疼的事情,即使搞懂了,之后遇到了也可能忘記。對(duì)于這個(gè)問題,諸多建議如下:

***:使用python3,就不用再糾結(jié)str于unicode了;但是這個(gè)很難開發(fā)者說了算;

第二:不要使用中文,注釋什么的都用英文;理想很豐滿,現(xiàn)實(shí)很難,只是導(dǎo)致大量的拼音;

第三:對(duì)于中文字符串,不要用str表示,而是用unicode表示;現(xiàn)實(shí)中也不好實(shí)施,大家都不愿意多寫一個(gè)u

第四:只在傳輸,或者持久化的時(shí)候?qū)nicode進(jìn)行encode,相反的過程時(shí)decode

第五:對(duì)于網(wǎng)絡(luò)接口,約定好編解碼格式,強(qiáng)烈建議使用utf-8

第六:看到UnicodeXXXError不要慌,如果XXX是Encode,那么一定是unicode轉(zhuǎn)str的時(shí)候出了問題;如果是Decode,一定是str轉(zhuǎn)unicode的時(shí)候出了問題。

參考

  • python codecs
  • python-specific-encodings
  • 字符編碼筆記:ASCII,Unicode 和 UTF-8
  • 玩轉(zhuǎn)Python讓人討厭的編碼問題  
責(zé)任編輯:龐桂玉 來源: Python開發(fā)者
相關(guān)推薦

2024-04-12 12:19:08

語言模型AI

2022-03-24 08:51:48

Redis互聯(lián)網(wǎng)NoSQL

2024-04-01 12:24:33

2023-09-15 12:00:01

API應(yīng)用程序接口

2021-03-22 10:05:59

netstat命令Linux

2023-09-08 08:20:46

ThreadLoca多線程工具

2021-09-11 10:41:27

PythonPickle模塊

2023-08-24 16:50:45

2024-06-05 11:43:10

2023-04-03 15:04:00

RPCPHP語言

2019-11-19 08:00:00

神經(jīng)網(wǎng)絡(luò)AI人工智能

2020-03-18 14:00:47

MySQL分區(qū)數(shù)據(jù)庫

2022-06-07 10:13:22

前端沙箱對(duì)象

2021-06-30 08:45:02

內(nèi)存管理面試

2022-08-15 15:39:23

JavaScript面向?qū)ο?/a>數(shù)據(jù)

2021-01-13 05:21:59

參數(shù)

2023-10-16 08:16:31

Bean接口類型

2023-03-06 21:29:41

mmap技術(shù)操作系統(tǒng)

2023-05-22 13:27:17

2023-09-02 21:27:09

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

麻豆国产尤物av尤物在线观看| 免费av手机在线观看| 中文字幕无码乱码人妻日韩精品| 波多野结衣的一区二区三区| 欧美日韩欧美一区二区| 天天综合五月天| 日本高清视频免费观看| 日韩精品电影一区亚洲| 久热精品视频在线观看| 五月天激情小说| 农村妇女一区二区| 午夜影院久久久| 亚洲午夜精品久久| 免费的黄色av| 激情成人午夜视频| 2024亚洲男人天堂| 日韩成人短视频| 中文字幕中文字幕精品| 日韩欧美一级在线播放| 不卡av免费在线| free性欧美| 国产精品久久久久国产精品日日 | 日本少妇裸体做爰| 日韩国产一区二区| 精品亚洲一区二区三区| 国产大片一区二区三区| 成人自拍av| 亚洲高清免费视频| ijzzijzzij亚洲大全| 成人高潮成人免费观看| 99riav久久精品riav| 91麻豆国产语对白在线观看| 国产精品无码粉嫩小泬| 国产精品一二| 久久免费视频在线| 青娱乐免费在线视频| 97色伦图片97综合影院| 色婷婷av一区二区三区在线观看| 欧美图片第一页| 日韩欧美天堂| 日韩精品在线影院| 国产 中文 字幕 日韩 在线| 波多野结衣欧美| 欧美成人精品高清在线播放 | 国产精品自拍99| 欧美午夜国产| 欧美国产第一页| 特级片在线观看| 综合久久亚洲| 欧美精品一二区| 玖玖爱这里只有精品| 999久久久精品国产| 深夜福利一区二区| xxxxx99| 成人中文在线| 精品国偷自产在线视频| 国产91在线播放九色| 久久中文亚洲字幕| 久久精品成人一区二区三区| 情侣偷拍对白清晰饥渴难耐| 91精品国产91久久综合| 久久伊人免费视频| 激情五月少妇a| 黄色日韩在线| 欧美孕妇毛茸茸xxxx| 男人天堂av在线播放| 免费人成在线不卡| 91网在线免费观看| 欧洲精品久久一区二区| 91女人视频在线观看| 欧美一区观看| 日本在线观看视频| 亚洲黄色性网站| 99视频在线免费播放| 中文字幕乱码在线播放| 欧美性色黄大片| 天堂中文av在线| 北条麻妃一区二区三区在线观看| 日韩高清欧美高清| 69视频在线观看免费| 91九色精品国产一区二区| 九九热最新视频//这里只有精品 | 国产精品无码专区| 一个色免费成人影院| 中文字幕精品一区二区精品| 99久久婷婷国产综合| 一区在线观看| 国产精品福利无圣光在线一区| 国产区精品在线| 成人av在线电影| 亚洲精品无人区| 超免费在线视频| 精品视频999| 国产十八熟妇av成人一区| 成人黄色小视频| 欧美精品久久久久a| 四虎影院在线免费播放| 国产精品亚洲视频| 欧美大陆一区二区| 最近中文字幕免费mv2018在线 | 欧美成人xxxxx| 欧美91在线|欧美| 日韩av在线高清| 懂色av懂色av粉嫩av| 久久精品盗摄| 超碰97人人在线| a黄色在线观看| 激情成人中文字幕| 亚洲三级在线视频| 国产精品欧美在线观看| 欧美国产精品va在线观看| 中文字幕日本视频| 北条麻妃国产九九精品视频| 亚洲综合网中心| 第84页国产精品| 日韩免费福利电影在线观看| 五月婷婷六月香| 欧美一级网站| 国产精品夜夜夜一区二区三区尤| av影片免费在线观看| 精品久久久免费| 野花视频免费在线观看| 欧美疯狂party性派对| 日韩美女视频免费看| 男人天堂网在线视频| 一区二区三区免费| 99国产精品久久久久久| 郴州新闻综合频道在线直播| 欧美在线视频播放| 欧美一级特黄aaaaaa| 亚洲图片欧美视频| 中文字幕第六页| 在线精品视频在线观看高清| 成人免费黄色网| 菠萝菠萝蜜在线视频免费观看 | 深爱五月综合网| 99精品视频精品精品视频 | 国产精品一级二级| 亚洲国产精品国自产拍av| 北条麻妃在线视频| 精品一区在线| 国产精品国模在线| 91porn在线观看| 欧美亚洲综合色| av在线播放中文字幕| 免费成人在线视频观看| 亚洲成人自拍视频| 亚洲毛片在线免费| 美日韩精品视频免费看| 国产草草影院ccyycom| 一区二区三区免费看视频| 成年人性生活视频| 欧美亚洲不卡| 国内精品久久国产| 在线免费看h| 亚洲新中文字幕| 亚洲天堂狠狠干| 亚洲嫩草精品久久| 日本wwwxx| 在线一区欧美| 日韩欧美精品在线不卡| 久久久久毛片| 久久精品国产一区二区三区| av网站免费播放| 亚洲国产va精品久久久不卡综合| 911亚洲精选| 国产精品黄色| 欧美三级网色| 国产aa精品| 久久人人爽国产| 你懂的视频在线观看| 精品视频资源站| 精品少妇久久久久久888优播| 成人av中文字幕| 欧美性猛交久久久乱大交小说| 精品国内自产拍在线观看视频 | 亚洲天堂2016| 黄色av电影网站| 日韩一区精品字幕| 亚洲小视频在线播放| 国产精品毛片av| 国产精品国产亚洲伊人久久 | 丰满人妻一区二区三区免费视频| 午夜电影一区二区三区| 国产精品久久久视频| 国产伦精品一区二区三区在线观看| 高清欧美精品xxxxx| 欧美精品羞羞答答| 大波视频国产精品久久| 欧美xx视频| 色综合男人天堂| 黄色片免费在线| 91精品国产综合久久蜜臀| 日韩黄色精品视频| 中文字幕亚洲电影| 亚洲av无码一区二区二三区| 国产一区二区三区四区五区入口| 欧美 日韩 国产 高清| 人人狠狠综合久久亚洲婷| 成人女人免费毛片| 日韩电影免费观看高清完整版在线观看| 欧美大片大片在线播放| 国产视频二区在线观看| 亚洲第一黄色网| 国产精品免费无遮挡| 欧美丝袜第一区| 免费网站观看www在线观| 国产欧美精品一区二区色综合朱莉| 国产精品二区视频| 久久精品国产精品亚洲精品| 免费观看日韩毛片| 欧美三级黄美女| 一区二区视频在线播放| 欧美人与牛zoz0性行为| 国产中文一区二区| 亚洲一区二区三区中文字幕在线观看 | 日韩欧美中文字幕精品| 在线观看国产精品入口男同| 日韩欧美在线视频日韩欧美在线视频 | 色久视频在线播放| 日韩欧美的一区| 91亚洲国产成人精品一区| 色香蕉久久蜜桃| 青青操免费在线视频| 一区二区三区免费看视频| 一级黄色片日本| 国产精品沙发午睡系列990531| 国产美女喷水视频| 91免费观看视频| 亚洲精品第二页| 成人午夜激情在线| 五月天丁香社区| 极品美女销魂一区二区三区免费| 色片在线免费观看| 久久精品国产一区二区| 爱情岛论坛vip永久入口| 久久久久国产精品一区三寸| 免费无遮挡无码永久视频| 激情文学一区| 18禁网站免费无遮挡无码中文| 亚洲高清二区| 日韩视频在线视频| 一本一本久久| 337p粉嫩大胆噜噜噜鲁| 亚洲男女自偷自拍| 97超碰青青草| 久久精品盗摄| 538任你躁在线精品免费| 日韩国产在线观看一区| 日韩av手机版| 久热成人在线视频| 九九九九九伊人| 国产精品91一区二区| 永久看看免费大片| av电影在线观看一区| jlzzjizz在线播放观看| 久久免费精品国产久精品久久久久| 37p粉嫩大胆色噜噜噜| 久久亚洲私人国产精品va媚药| 97伦伦午夜电影理伦片| 欧美国产激情一区二区三区蜜月| 天美传媒免费在线观看| 亚洲视频一区二区免费在线观看| 精品爆乳一区二区三区无码av| 亚洲自拍偷拍欧美| 一级黄色免费网站| 欧美中文字幕不卡| 国产精品一级二级| 亚洲精品国产综合久久| 国产在线日本| 免费av在线一区| 国产极品在线观看| 国产精品美乳在线观看| 国语精品视频| 久久国产精品免费一区| 日韩一区欧美| 国产精品视频网站在线观看| 午夜亚洲影视| 欧美激情国内自拍| kk眼镜猥琐国模调教系列一区二区| 波多野结衣办公室33分钟| 中文av字幕一区| 青青操国产视频| 一本久久综合亚洲鲁鲁五月天 | 精品一区二区精品| 精品久久久久一区二区| 国产亚洲欧美一级| 免费在线视频观看| 91福利在线导航| 亚洲伦理在线观看| 夜夜嗨av色综合久久久综合网| 尤物yw193can在线观看| 国产z一区二区三区| 国产精品一区二区精品视频观看| 国产一区二区高清视频| 欧美亚洲国产一区| 国产精品成人久久电影| 美国欧美日韩国产在线播放 | 国产日本亚洲高清| 久久久久黄色片| 欧美探花视频资源| 四虎免费在线观看| 久久久精品一区二区| 在线最新版中文在线| 99porn视频在线| 日韩免费久久| 粗暴91大变态调教| 99久久国产综合精品色伊| 日韩欧美国产成人精品免费| 日韩欧美精品网址| 亚洲成人77777| 久久精品国产亚洲7777| 欧美三级网址| 久久99精品久久久久久久青青日本| 天天av综合| 爱爱爱爱免费视频| 国产女同互慰高潮91漫画| 国产精品男女视频| 精品国产网站在线观看| 国产盗摄在线观看| 国产欧美日韩亚洲精品| 精品国产91| 日韩精品一区二区三区久久| 99在线视频精品| 国产在线视频第一页| 91精品国产全国免费观看| 日本免费中文字幕在线| 国产精品jvid在线观看蜜臀| 偷窥自拍亚洲色图精选| 久久久亚洲国产精品| 成人美女视频在线看| 美女的奶胸大爽爽大片| 欧美一级欧美一级在线播放| 欧美激情午夜| 91精品久久久久久久久久久久久| 精品一二三区| 日韩毛片在线免费看| 久久嫩草精品久久久精品| 亚洲欧美偷拍一区| 亚洲免费精彩视频| 免费亚洲电影| 日本在线播放一区| 男男视频亚洲欧美| 中文字幕资源站| 欧美一级午夜免费电影| 中文国产字幕在线观看| 999视频在线免费观看| 伊人久久综合| 亚洲色图14p| 色婷婷av一区| 免费网站免费进入在线| 成人亚洲激情网| 最新欧美人z0oozo0| 中文字幕18页| 欧美日韩国产激情| 日韩一区二区三区中文字幕| 国产精品wwww| 国产精品久久久久一区二区三区厕所| 黄色小视频免费网站| 亚洲综合一二区| 午夜18视频在线观看| 国产不卡在线观看| 99久久99热这里只有精品| 亚洲成人激情小说| 欧美性猛交xxxx乱大交| yourporn在线观看视频| 国产日韩在线看| 好看不卡的中文字幕| 黄色片视频免费观看| 欧美性大战久久| a黄色片在线观看| 久久艳妇乳肉豪妇荡乳av| 日本一区中文字幕| 国产女人被狂躁到高潮小说| 亚洲国产又黄又爽女人高潮的| 欧美aaa大片视频一二区| 自拍偷拍亚洲色图欧美| 福利一区在线观看| 日韩精品在线一区二区三区| 久久这里有精品| 亚洲第一二三区| 手机在线国产视频| 黄色成人av在线| 久久黄色美女电影| 精品乱码一区| 国产一区二区毛片| 黄色大片网站在线观看| 波霸ol色综合久久| 欧美91在线| 日日夜夜精品视频免费观看| 日韩欧美国产黄色| 国产一区久久精品| 欧美一卡2卡3卡4卡无卡免费观看水多多 | 中文字幕在线视频一区| 色婷婷中文字幕| 国产噜噜噜噜噜久久久久久久久| 亚洲天堂成人| 北条麻妃在线观看视频| 亚洲另类激情图| 北条麻妃在线一区二区免费播放 |