談?wù)刾ython2,3中的str柑爸、unicode

前言

本文首先對(duì)Unicode與UTF-8的區(qū)別做一個(gè)解釋吵护,如果已了解,可跳過(guò)該部分表鳍。然后會(huì)分別對(duì)python2馅而,3中的str、unicode進(jìn)行講解譬圣。有問題的地方瓮恭,歡迎交流。

Unicode與UTF-8

  • Unicode 是「字符集」
  • UTF-8 是「編碼規(guī)則」
  • 字符集:為每一個(gè)「字符」分配一個(gè)唯一的 ID(學(xué)名為碼位 / 碼點(diǎn) / Code Point)
  • 編碼規(guī)則:將「碼位」轉(zhuǎn)換為字節(jié)序列的規(guī)則(編碼/解碼 可以理解為 加密/解密 的過(guò)程)

廣義的 Unicode 是一個(gè)標(biāo)準(zhǔn)厘熟,定義了一個(gè)字符集以及一系列的編碼規(guī)則屯蹦,即 Unicode 字符集和 UTF-8、UTF-16绳姨、UTF-32 等等編碼……

Unicode 字符集為每一個(gè)字符分配一個(gè)碼位登澜,例如「知」的碼位是 30693,記作 U+77E5(30693 的十六進(jìn)制為 0x77E5)就缆。

U+ 0000 ~ U+ 007F: 0XXXXXXX
U+ 0080 ~ U+ 07FF: 110XXXXX 10XXXXXX
U+ 0800 ~ U+ FFFF: 1110XXXX 10XXXXXX 10XXXXXX
U+10000 ~ U+1FFFF: 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX

根據(jù)上表中的編碼規(guī)則帖渠,之前的「知」字的碼位 U+77E5 屬于第三行的范圍:

       7    7    E    5    
    0111 0111 1110 0101    二進(jìn)制的 77E5
--------------------------
    0111   011111   100101 二進(jìn)制的 77E5
1110XXXX 10XXXXXX 10XXXXXX 模版(上表第三行)
11100111 10011111 10100101 代入模版
   E   7    9   F    A   5

這就是將 U+77E5 按照 UTF-8 編碼為字節(jié)序列 E79FA5 的過(guò)程。

python2中的str和unicode

str與unicode

Python2中:

  • str格式本質(zhì)含義是“某種編碼格式”竭宰,絕大多數(shù)情況下空郊,被引號(hào)框起來(lái)的字符串份招,就是str,它本身存儲(chǔ)的就是字節(jié)碼(bytes)狞甚。

    >>> s = "我愛我的祖國(guó)"
    >>> s
    '\xce\xd2\xb0\xae\xce\xd2\xb5\xc4\xd7\xe6\xb9\xfa'
    

    那么這個(gè)字節(jié)碼是什么格式的锁摔。

    如果這段代碼是在解釋器上輸入的,那么這個(gè)s的格式就是解釋器的編碼格式哼审,對(duì)于windows的cmd而言谐腰,就是gbk。

    如果將段代碼是保存后才執(zhí)行的涩盾,比如存儲(chǔ)為utf-8十气,那么在解釋器載入這段程序的時(shí)候,就會(huì)將s初始化為utf-8編碼春霍。

    下面是我在cmd中的嘗試

    >>> s = "我愛我的祖國(guó)"
    >>> print chardet.detect(s)
    {'confidence': 0.99, 'language': 'Chinese', 'encoding': 'GB2312'}
    

    在我的測(cè)試過(guò)程中狰右,有些中文會(huì)被識(shí)別成別的編碼抢野,不是GB2312,如下識(shí)別成俄語(yǔ)編碼铲汪,這個(gè)可能跟windows有關(guān)瓤漏。

    >>> s = "加油"
    >>> print chardet.detect(s)
    {'confidence': 0.7679697235616183, 'language': 'Russian', 'encoding': 'KOI8-R'}
    >>> s = "中國(guó)"
    >>> print chardet.detect(s)
    {'confidence': 0.7679697235616183, 'language': 'Russian', 'encoding': 'IBM855'}
    
  • unicode類型的含義就是“用unicode編碼的字符串”很魂。unicode()是單獨(dú)的样悟,不像str()是byte類型隙弛。

    >>> s = u"我愛我的祖國(guó)"
    >>> s
    u'\u6211\u7231\u6211\u7684\u7956\u56fd'
    >>> print type(s)
    <type 'unicode'>
    >>> print chardet.detect(s)
    TypeError: Expected object of type bytes or bytearray, got: <type 'unicode'>
    

    引號(hào)前面的u表示這里創(chuàng)建的是一個(gè)Unicode字符串

    Python在進(jìn)入2.0版后正式定義了了Unicode字符串這個(gè)奇怪的特性,目的就是為了處理太多種語(yǔ)言編碼的文本喧伞。從那時(shí)開始走芋,Python語(yǔ)言中的字符串類型就分為兩種:一種是傳統(tǒng)的Python字符串(各種花樣編碼),另一種則是新出現(xiàn)的Unicode絮识。

encode與decode

下面的測(cè)試绿聘,都將在代碼存儲(chǔ)為utf-8后嗽上,再由解釋器執(zhí)行次舌,也就是說(shuō)str將初始化為utf-8編碼

在python2中的解碼(decode)、編碼(encode)操作如下:

import chardet
s = "我愛我的祖國(guó)"
print type(s)
print chardet.detect(s)
u = s.decode("UTF-8")
print type(u)
s = u.encode("gbk")
print type(s)
print chardet.detect(s)

'''
<type 'str'>
{'confidence': 0.99, 'language': '', 'encoding': 'utf-8'}
<type 'unicode'>
<type 'str'>
{'confidence': 0.99, 'language': 'Chinese', 'encoding': 'GB2312'}
'''

從輸出可看出兽愤,s為utf-8編碼的字符串彼念,用decode()將s解碼為unicode對(duì)象。

對(duì)解碼后的unicode對(duì)象進(jìn)行編碼浅萧,用encode()將s編碼為utf-8對(duì)象逐沙。

那么,再看下洼畅,下面這個(gè)情況吩案,s作為字符串,不僅有decode()帝簇,還有encode()徘郭。

s = "我愛我的祖國(guó)"
print hasattr(s, "decode")
print hasattr(s, "encode")

'''
True
True
'''

decode()我們是已經(jīng)使用過(guò)了靠益,將某種編碼的字符串解碼成unicode對(duì)象。那么是否能直接將字符串改成另外一種編碼呢残揉?這就是str的encode()胧后,為我們省去了decode()的過(guò)程。但這里也有一個(gè)坑抱环!

s = "我愛我的祖國(guó)"
s = s.encode("gbk")

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

嘗試將utf-8的str直接變成gbk編碼壳快,報(bào)錯(cuò)了,報(bào)錯(cuò)信息翻譯如下:

'ascii'編解碼器無(wú)法解碼位置0的字節(jié)0xce:序號(hào)不在范圍(128)

可以看出镇草,程序嘗試用ascii碼對(duì)s進(jìn)行解碼眶痰,之所以會(huì)使用ascii,這與系統(tǒng)的默認(rèn)編碼有關(guān):

import sys
print sys.getdefaultencoding()

'''
ascii
'''

那么梯啤,我們將sys的默認(rèn)編碼設(shè)置成utf-8凛驮,就可以正常運(yùn)行了

import sys
reload(sys)
sys.setdefaultencoding('utf-8')
s = "我愛我的祖國(guó)"
print chardet.detect(s)
s = s.encode("gbk")
print chardet.detect(s)

'''
{'confidence': 0.99, 'language': '', 'encoding': 'utf-8'}
{'confidence': 0.99, 'language': 'Chinese', 'encoding': 'GB2312'}
'''

其實(shí)s.encode("gbk")就相當(dāng)于

s.decode(defaultencoding),encode('utf-8')

python3中的str和unicode

  • str格式的定義變更為”Unicode類型的字符串“,也就是說(shuō)在默認(rèn)情況下条辟,被引號(hào)框起來(lái)的字符串黔夭,是使用Unicode編碼的。也就是說(shuō)unicode類型在python3中沒有了羽嫡,python3中的str就相當(dāng)于python2中的unicode本姥。

    在python3里,str將不再是python2中的字節(jié)碼杭棵,不能作為chardet.detect的參數(shù)婚惫。

    import chardet
    s = "我愛我的祖國(guó)"
    print (type(s))
    print (chardet.detect(s))
    
    '''
    <class 'str'>
    TypeError: Expected object of type bytes or bytearray, got: <class 'str'>
    '''
    

    str也沒有了解碼方法decode()

    s = "我愛我的祖國(guó)"
    print (hasattr(s, "decode"))
    print (hasattr(s, "encode"))
    
    '''
    False
    True
    '''
    

    python3中源碼文件默認(rèn)使用utf-8編碼,使得以下代碼是合法的

    >>> 中國(guó) = 'china' 
    >>>print(中國(guó)) 
    china
    

    下面這個(gè) 不知道該怎么解釋魂爪,不是以u(píng)nicode編碼的形式輸出了

    >>> s = "我愛我的祖國(guó)"
    >>> s
    '我愛我的祖國(guó)'
    
  • 而“不是Unicode的某種編碼格式”先舷,比如UTF-8、GBK滓侍,這些編碼方式被定義為了bytes蒋川,這里的bytes和python2中的str有很多相似的地方。

參考

  1. 知乎(Unicode 和 UTF-8 有何區(qū)別撩笆?)
  2. 知乎(Python2和3中關(guān)于str和unicode以及UTF-8的更改到底是什么意思捺球?)
  3. Python中的str與unicode處理方法
  4. 菜鳥教程(字符串)
  5. 菜鳥教程(Python2.x與3.x版本區(qū)別)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市夕冲,隨后出現(xiàn)的幾起案子氮兵,更是在濱河造成了極大的恐慌,老刑警劉巖歹鱼,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泣栈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)南片,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門篙悯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人铃绒,你說(shuō)我怎么就攤上這事鸽照。” “怎么了颠悬?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵矮燎,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我赔癌,道長(zhǎng)诞外,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任灾票,我火速辦了婚禮峡谊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘刊苍。我一直安慰自己既们,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布正什。 她就那樣靜靜地躺著啥纸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪婴氮。 梳的紋絲不亂的頭發(fā)上斯棒,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音主经,去河邊找鬼荣暮。 笑死,一個(gè)胖子當(dāng)著我的面吹牛罩驻,可吹牛的內(nèi)容都是我干的穗酥。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼鉴腻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼迷扇!你這毒婦竟也來(lái)了百揭?” 一聲冷哼從身側(cè)響起爽哎,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎器一,沒想到半個(gè)月后课锌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年渺贤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了雏胃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡志鞍,死狀恐怖瞭亮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情固棚,我是刑警寧澤统翩,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站此洲,受9級(jí)特大地震影響厂汗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜呜师,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一娶桦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧汁汗,春花似錦衷畦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至送爸,卻和暖如春铛嘱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背袭厂。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工墨吓, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人纹磺。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓帖烘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親橄杨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子秘症,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容