亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解Python2.x中對(duì)Unicode編碼的使用

 更新時(shí)間:2015年04月03日 09:30:45   作者:ERIC MORITZ  
這篇文章主要介紹了詳解Python2.x中對(duì)Unicode編碼的使用,Python3中Unicode被作為默認(rèn)的編碼來使用,而在目前仍被廣泛應(yīng)用的Python2的版本中Unicode卻是一個(gè)在使用中需要注意的地方,需要的朋友可以參考下

我確定有很多關(guān)于Unicode和Python的說明,但為了方便自己的理解使用,我還是打算再寫一些關(guān)于它們的東西。

 
字節(jié)流 vs Unicode對(duì)象

我們先來用Python定義一個(gè)字符串。當(dāng)你使用string類型時(shí),實(shí)際上會(huì)儲(chǔ)存一個(gè)字節(jié)串。
 

[ a ][ b ][ c ] = "abc"
[ 97 ][ 98 ][ 99 ] = "abc"

在這個(gè)例子里,abc這個(gè)字符串是一個(gè)字節(jié)串。97.,98,,99是ASCII碼。Python 2.x版本的一個(gè)不足之處就是默認(rèn)將所有的字符串當(dāng)做ASCII來對(duì)待。不幸的是,ASCII在拉丁式字符集里是最不常見的標(biāo)準(zhǔn)。

ASCII是用前127個(gè)數(shù)字來做字符映射。像windows-1252和UTF-8這樣的字符映射有相同的前127個(gè)字符。在你的字符串里每個(gè)字節(jié)的值低于127的時(shí)候是安全的混合字符串編碼。然而作這個(gè)假設(shè)是件很危險(xiǎn)的事情,下面還將會(huì)提到。

當(dāng)你的字符串里有字節(jié)的值大于126的時(shí)候就會(huì)出現(xiàn)問題了。我們來看一個(gè)用windows-1252編碼的字符串。Windows-1252里的字符映射是8位的字符映射,那么總共就會(huì)有256個(gè)字符。前127個(gè)跟ASCII是一樣的,接下來的127個(gè)是由windows-1252定義的其他字符。
 

A windows-1252 encoded string looks like this:
[ 97 ] [ 98 ] [ 99 ] [ 150 ] = "abc–"

Windows-1252仍然是一個(gè)字節(jié)串,但你有沒有看到最后一個(gè)字節(jié)的值是大于126的。如果Python試著用默認(rèn)的ASCII標(biāo)準(zhǔn)來解碼這個(gè)字節(jié)流,它就會(huì)報(bào)錯(cuò)。我們來看當(dāng)Python解碼這個(gè)字符串的時(shí)候會(huì)發(fā)生什么:
 

>>> x = "abc" + chr(150)
>>> print repr(x)
'abc\x96'
>>> u"Hello" + x
Traceback (most recent call last):
 File "<stdin>", line 1, in ?
UnicodeDecodeError: 'ASCII' codec can't decode byte 0x96 in position 3: ordinal not in range(128)

我們來用UTF-8來編碼另一個(gè)字符串:
 

A UTF-8 encoded string looks like this:
[ 97 ] [ 98 ] [ 99 ] [ 226 ] [ 128 ] [ 147 ] = "abc–"
[0x61] [0x62] [0x63] [0xe2] [ 0x80] [ 0x93] = "abc-"

如果你拿起看你熟悉的Unicode編碼表,你會(huì)發(fā)現(xiàn)英文的破折號(hào)對(duì)應(yīng)的Unicode編碼點(diǎn)為8211(0×2013)。這個(gè)值大于ASCII最大值127。大于一個(gè)字節(jié)能夠存儲(chǔ)的值。因?yàn)?211(0×2013)是兩個(gè)字節(jié),UTF-8必須利用一些技巧告訴系統(tǒng)存儲(chǔ)一個(gè)字符需要三個(gè)字節(jié)。我們?cè)賮砜串?dāng)Python準(zhǔn)備用默認(rèn)的ASCII來編碼一個(gè)里面有字符的值大于126的UTF-8編碼字符串。
 

>>> x = "abc\xe2\x80\x93"
>>> print repr(x)
'abc\xe2\x80\x93'
>>> u"Hello" + x
Traceback (most recent call last):
 File "<stdin>", line 1, in ?
UnicodeDecodeError: 'ASCII' codec can't decode byte 0xe2 in position 3: ordinal not in range(128)

你可以看到,Python一直是默認(rèn)使用ASCII編碼。當(dāng)它處理第4個(gè)字符的時(shí)候,因?yàn)樗闹禐?26大于126,所以Python拋出了錯(cuò)誤。這就是混合編碼所帶來的問題。

 
解碼字節(jié)流

在一開始學(xué)習(xí)Python Unicode 的時(shí)候,解碼這個(gè)術(shù)語可能會(huì)讓人很疑惑。你可以把字節(jié)流解碼成一個(gè)Unicode對(duì)象,把一個(gè)Unicode 對(duì)象編碼為字節(jié)流。

Python需要知道如何將字節(jié)流解碼為Unicode對(duì)象。當(dāng)你拿到一個(gè)字節(jié)流,你調(diào)用它的“解碼方法來從它創(chuàng)建出一個(gè)Unicode對(duì)象。

你最好是盡早的將字節(jié)流解碼為Unicode。
 

>>> x = "abc\xe2\x80\x93"
>>> x = x.decode("utf-8")
>>> print type(x)
<type 'unicode'>
>>> y = "abc" + chr(150)
>>> y = y.decode("windows-1252")
>>> print type(y)
>>> print x + y
abc–abc–

 
將Unicode編碼為字節(jié)流

Unicode對(duì)象是一個(gè)文本的編碼不可知論的代表。你不能簡(jiǎn)單地輸出一個(gè)Unicode對(duì)象。它必須在輸出前被變成一個(gè)字節(jié)串。Python會(huì)很適合做這樣的工作,盡管Python將Unicode編碼為字節(jié)流時(shí)默認(rèn)是適用ASCII,這個(gè)默認(rèn)的行為會(huì)成為很多讓人頭疼的問題的原因。
 

>>> u = u"abc\u2013"
>>> print u
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2013' in position 3: ordinal not in range(128)
>>> print u.encode("utf-8")
abc–

 
使用codecs模塊

codecs模塊能在處理字節(jié)流的時(shí)候提供很大幫助。你可以用定義的編碼來打開文件并且你從文件里讀取的內(nèi)容會(huì)被自動(dòng)轉(zhuǎn)化為Unicode對(duì)象。

試試這個(gè):
 

>>> import codecs
>>> fh = codecs.open("/tmp/utf-8.txt", "w", "utf-8")
>>> fh.write(u"\u2013")
>>> fh.close()

它所做的就是拿到一個(gè)Unicode對(duì)象然后將它以u(píng)tf-8編碼寫入到文件。你也可以在其他的情況下這么使用它。

試試這個(gè):

當(dāng)從一個(gè)文件讀取數(shù)據(jù)的時(shí)候,codecs.open 會(huì)創(chuàng)建一個(gè)文件對(duì)象能夠自動(dòng)將utf-8編碼文件轉(zhuǎn)化為一個(gè)Unicode對(duì)象。

我們接著上面的例子,這次使用urllib流。
 

>>> stream = urllib.urlopen("http://www.google.com")
>>> Reader = codecs.getreader("utf-8")
>>> fh = Reader(stream)
>>> type(fh.read(1))
<type 'unicode'>
>>> Reader
<class encodings.utf_8.StreamReader at 0xa6f890>

單行版本:
 

>>> fh = codecs.getreader("utf-8")(urllib.urlopen("http://www.google.com"))
>>> type(fh.read(1))

你必須對(duì)codecs模塊十分小心。你傳進(jìn)去的東西必須是一個(gè)Unicode對(duì)象,否則它會(huì)自動(dòng)將字節(jié)流作為ASCII進(jìn)行解碼。
 

>>> x = "abc\xe2\x80\x93" # our "abc-" utf-8 string
>>> fh = codecs.open("/tmp/foo.txt", "w", "utf-8")
>>> fh.write(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.5/codecs.py", line 638, in write
 return self.writer.write(data)
File "/usr/lib/python2.5/codecs.py", line 303, in write
 data, consumed = self.encode(object, self.errors)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 3: ordinal not in range(128)

哎呦我去,Python又開始用ASCII來解碼一切了。
將UTF-8字節(jié)流切片的問題

因?yàn)橐粋€(gè)UTF-8編碼串是一個(gè)字節(jié)列表,len( )和切片操作無法正常工作。首先用我們之前用的字符串。
 

[ 97 ] [ 98 ] [ 99 ] [ 226 ] [ 128 ] [ 147 ] = "abc–"

接下來做以下的:
 

>>> my_utf8 = "abc–"
>>> print len(my_utf8)
6

神馬?它看起來是4個(gè)字符,但是len的結(jié)果說是6。因?yàn)閘en計(jì)算的是字節(jié)數(shù)而不是字符數(shù)。
 

>>> print repr(my_utf8)
'abc\xe2\x80\x93'

現(xiàn)在我們來切分這個(gè)字符串。
 

>>> my_utf8[-1] # Get the last char
'\x93'

我去,切分結(jié)果是最后一字節(jié),不是最后一個(gè)字符。

為了正確的切分UTF-8,你最好是解碼字節(jié)流創(chuàng)建一個(gè)Unicode對(duì)象。然后就能安全的操作和計(jì)數(shù)了。
 

>>> my_unicode = my_utf8.decode("utf-8")
>>> print repr(my_unicode)
u'abc\u2013'
>>> print len(my_unicode)
4
>>> print my_unicode[-1]
–

 
當(dāng)Python自動(dòng)地編碼/解碼

在一些情況下,當(dāng)Python自動(dòng)地使用ASCII進(jìn)行編碼/解碼的時(shí)候會(huì)拋出錯(cuò)誤。

第一個(gè)案例是當(dāng)它試著將Unicode和字節(jié)串合并在一起的時(shí)候。
 

>>> u"" + u"\u2019".encode("utf-8")
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0:  ordinal not in range(128)

在合并列表的時(shí)候會(huì)發(fā)生同樣的情況。Python在列表里有string和Unicode對(duì)象的時(shí)候會(huì)自動(dòng)地將字節(jié)串解碼為Unicode。
 

>>> ",".join([u"This string\u2019s unicode", u"This string\u2019s utf-8".encode("utf-8")])
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 11: ordinal not in range(128)

或者當(dāng)試著格式化一個(gè)字節(jié)串的時(shí)候:
 

>>> "%s\n%s" % (u"This string\u2019s unicode", u"This string\u2019s utf-8".encode("utf-8"),)
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 11: ordinal not in range(128)

基本上當(dāng)你把Unicode和字節(jié)串混在一起用的時(shí)候,就會(huì)導(dǎo)致出錯(cuò)。

在這個(gè)例子里面,你創(chuàng)建一個(gè)utf-8文件,然后往里面添加一些Unicode對(duì)象的文本。就會(huì)報(bào)UnicodeDecodeError錯(cuò)誤。
 

>>> buffer = []
>>> fh = open("utf-8-sample.txt")
>>> buffer.append(fh.read())
>>> fh.close()
>>> buffer.append(u"This string\u2019s unicode")
>>> print repr(buffer)
['This file\xe2\x80\x99s got utf-8 in it\n', u'This string\u2019s unicode']
>>> print "\n".join(buffer)
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 9: ordinal not in range(128)

你可以使用codecs模塊把文件作為Unicode加載來解決這個(gè)問題。
 

>>> import codecs
>>> buffer = []
>>> fh = open("utf-8-sample.txt", "r", "utf-8")
>>> buffer.append(fh.read())
>>> fh.close()
>>> print repr(buffer)
[u'This file\u2019s got utf-8 in it\n', u'This string\u2019s unicode']
>>> buffer.append(u"This string\u2019s unicode")
>>> print "\n".join(buffer)
This file's got utf-8 in it
 
This string's unicode

正如你看到的,由codecs.open 創(chuàng)建的流在當(dāng)數(shù)據(jù)被讀取的時(shí)候自動(dòng)地將比特串轉(zhuǎn)化為Unicode。

 
最佳實(shí)踐

1.最先解碼,最后編碼

2.默認(rèn)使用utf-8編碼

3.使用codecs和Unicode對(duì)象來簡(jiǎn)化處理

最先解碼意味著無論何時(shí)有字節(jié)流輸入,需要盡早將輸入解碼為Unicode。這會(huì)防止出現(xiàn)len( )和切分utf-8字節(jié)流發(fā)生問題。

最后編碼意味著只有你打算將文本輸出到某個(gè)地方時(shí),才把它編碼為字節(jié)流。這個(gè)輸出可能是一個(gè)文件,一個(gè)數(shù)據(jù)庫,一個(gè)socket等等。只有在處理完成之后才編碼unicode對(duì)象。最后編碼也意味著,不要讓Python為你編碼Unicode對(duì)象。Python將會(huì)使用ASCII編碼,你的程序會(huì)崩潰。

默認(rèn)使用UTF-8編碼意味著:因?yàn)閁TF-8可以處理任何Unicode字符,所以你最好用它來替代windows-1252和ASCII。

codecs模塊能夠讓我們?cè)谔幚碇T如文件或socket這樣的流的時(shí)候能少踩一些坑。如果沒有codecs提供的這個(gè)工具,你就必須將文件內(nèi)容讀取為字節(jié)流,然后將這個(gè)字節(jié)流解碼為Unicode對(duì)象。

codecs模塊能夠讓你快速的將字節(jié)流轉(zhuǎn)化為Unicode對(duì)象,省去很多麻煩。

 
解釋UTF-8

最后的部分是讓你能對(duì)UTF-8有一個(gè)入門的了解,如果你是個(gè)超級(jí)極客可以無視這一段。

利用UTF-8,任何在127和255之間的字節(jié)是特別的。這些字節(jié)告訴系統(tǒng)這些字節(jié)是多字節(jié)序列的一部分。
 

Our UTF-8 encoded string looks like this:
[ 97 ] [ 98 ] [ 99 ] [ 226 ] [ 128 ] [ 147 ] = "abc–"

最后3字節(jié)是一個(gè)UTF-8多字節(jié)序列。如果你把這三個(gè)字節(jié)里的第一個(gè)轉(zhuǎn)化為2進(jìn)制可以看到以下的結(jié)果:
 

11100010

前3比特告訴系統(tǒng)它開始了一個(gè)3字節(jié)序列226,128,147。

那么完整的字節(jié)序列。
 

11100010 10000000 10010011

然后你對(duì)三字節(jié)序列運(yùn)用下面的掩碼。(詳見這里

 
1110xxxx 10xxxxxx 10xxxxxx
XXXX0010 XX000000 XX010011 Remove the X's
0010    000000  010011 Collapse the numbers
00100000 00010011     Get Unicode number 0x2013, 8211 The "–"

這里僅僅是關(guān)于UTF-8的一些入門的基本知識(shí),如果想知道更多的細(xì)節(jié),可以去看UTF-8的維基頁面。

相關(guān)文章

  • Python調(diào)用Tkinter示例淺析

    Python調(diào)用Tkinter示例淺析

    這篇文章主要介紹了Python調(diào)用Tkinter示例,通過在Python程序中設(shè)計(jì)按鈕,可以方便用戶調(diào)用Python程序,從而達(dá)到快速、自動(dòng)化、高效的目的,提高用戶體驗(yàn)和工作效率
    2023-02-02
  • python相對(duì)企業(yè)語言優(yōu)勢(shì)在哪

    python相對(duì)企業(yè)語言優(yōu)勢(shì)在哪

    在本篇文章里小編給大家分享的是關(guān)于python相對(duì)企業(yè)語言優(yōu)勢(shì)以及相關(guān)知識(shí)點(diǎn),需要的朋友們可以參考下。
    2020-06-06
  • Python中方法的缺省參數(shù)問題解讀

    Python中方法的缺省參數(shù)問題解讀

    這篇文章主要介紹了Python中方法的缺省參數(shù)問題解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 用python生成(動(dòng)態(tài)彩色)二維碼的方法(使用myqr庫實(shí)現(xiàn))

    用python生成(動(dòng)態(tài)彩色)二維碼的方法(使用myqr庫實(shí)現(xiàn))

    今天小編就為大家分享一篇用python生成(動(dòng)態(tài)彩色)二維碼的方法(使用myqr庫實(shí)現(xiàn)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • python之excel文件(.xls文件)處理方式

    python之excel文件(.xls文件)處理方式

    這篇文章主要介紹了python之excel文件(.xls文件)處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • Django框架實(shí)現(xiàn)的分頁demo示例

    Django框架實(shí)現(xiàn)的分頁demo示例

    這篇文章主要介紹了Django框架實(shí)現(xiàn)的分頁demo,結(jié)合實(shí)例形式分析了Django框架分頁的步驟、原理、相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下
    2019-05-05
  • python os模塊和fnmatch模塊的使用介紹

    python os模塊和fnmatch模塊的使用介紹

    這篇文章主要介紹了python os模塊和fnmatch模塊的使用介紹,幫助大家更好的理解和學(xué)習(xí)使用python,感興趣的朋友可以了解下
    2021-03-03
  • python3中@dataclass的實(shí)現(xiàn)示例

    python3中@dataclass的實(shí)現(xiàn)示例

    @dataclass?是 Python 3.7 引入的一個(gè)裝飾器,用于方便地定義符合數(shù)據(jù)類協(xié)議的類,本文主要介紹了python3中@dataclass的實(shí)現(xiàn)示例,感興趣的可以了解一下
    2024-02-02
  • 徹底理解Python中的yield關(guān)鍵字

    徹底理解Python中的yield關(guān)鍵字

    今天小編就為大家分享一篇關(guān)于徹底理解Python中的yield關(guān)鍵字,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • python檢測(cè)某個(gè)變量是否有定義的方法

    python檢測(cè)某個(gè)變量是否有定義的方法

    這篇文章主要介紹了python檢測(cè)某個(gè)變量是否有定義的方法,實(shí)例分析了Python常用的變量判定技巧,需要的朋友可以參考下
    2015-05-05

最新評(píng)論