python encode

背景知識

ASCII編碼:

最早的計算機(jī)在設(shè)計時采用8個bit作為1個Byte,所以,一個字節(jié)能表示的最大的整數(shù)就是255(2進(jìn)制11111111=10進(jìn)制255)蝗拿,由于計算機(jī)是美國人發(fā)明的,因此,最早只有127(<255)個字符被編碼到計算機(jī)里谎懦,也就是大小寫英文字母、數(shù)字和一些符號溃斋,因此只需要一個字節(jié)就可以表示所有的大小寫英文字母界拦、數(shù)字、符號盐类。
注意??ASCII編碼每個字符占相同的 1 個Byte
這個每個字符只占位一個Byte的編碼表被稱為ASCII編碼寞奸,比如大寫字母A的編碼是65,小寫字母z的編碼是122在跳。

中文GB2312編碼枪萄,日文Shift_JIS編碼,韓文Euc-kr編碼:

顯然猫妙,只占一個字節(jié)的ASCII編碼處理中文是不夠的瓷翻。想要表示所有的中文字符至少需要兩個字節(jié),而且還不能和ASCII編碼沖突割坠,所以齐帚,中國制定了GB2312編碼,用來把中文編進(jìn)去彼哼。
全世界有上百種語言对妄,日本把日文編到Shift_JIS里,韓國把韓文編到Euc-kr里敢朱。
各國有各國的標(biāo)準(zhǔn)剪菱,就會不可避免地出現(xiàn)沖突,結(jié)果就是拴签,在多語言混合的文本中孝常,顯示出來會有亂碼。

Unicode編碼:

因此蚓哩,Unicode編碼應(yīng)運而生构灸。Unicode把所有語言都統(tǒng)一到一套編碼里,這樣就不會再有亂碼問題了岸梨。
Unicode標(biāo)準(zhǔn)也在不斷發(fā)展喜颁,但最常用的是用兩個字節(jié)表示一個字符(如果要用到非常偏僻的字符稠氮,就需要4個字節(jié))。現(xiàn)代操作系統(tǒng)和大多數(shù)編程語言都直接支持Unicode洛巢。
注意??unicode編碼每個字符占同樣的Bytes數(shù)括袒,通常為 2 個Bytes
現(xiàn)在,捋一捋ASCII編碼和Unicode編碼的區(qū)別:

  • ASCII編碼是1個字節(jié)稿茉,而Unicode編碼通常是2個字節(jié)锹锰。
  • 字母A用ASCII編碼是十進(jìn)制的65,二進(jìn)制的01000001漓库;
  • 如果把ASCII編碼的A用Unicode編碼恃慧,只需要在前面補(bǔ)0就可以,因此渺蒿,A的Unicode編碼是00000000 01000001痢士;
  • 漢字「中」已經(jīng)超出了ASCII編碼的范圍,用Unicode編碼是十進(jìn)制的20013茂装,二進(jìn)制的01001110 00101101怠蹂。

utf-8編碼:

新的問題又出現(xiàn)了:如果統(tǒng)一成Unicode編碼,亂碼問題從此消失了少态。但是城侧,如果你寫的文本基本上全部是英文的話,用Unicode編碼比ASCII編碼需要多一倍的存儲空間彼妻,在存儲和傳輸上就十分不劃算嫌佑。所以,本著節(jié)約的精神侨歉,又出現(xiàn)了把Unicode編碼轉(zhuǎn)化為“可變長編碼”的UTF-8編碼屋摇。
注意??utf-8編碼每個字符占不同的Bytes數(shù)
UTF-8編碼把一個Unicode字符根據(jù)不同的數(shù)字大小編碼成1-6個字節(jié):

  • 常用的英文字母被編碼成1個字節(jié),
  • 漢字通常是3個字節(jié)幽邓,
  • 只有很生僻的字符才會被編碼成4-6個字節(jié)炮温。

這種編碼方式像哈夫曼編碼(Huffman Coding)一樣是可變長編碼(VLC)的一種,傳輸?shù)奈谋景罅坑⑽淖址6妫肬TF-8編碼就能節(jié)省空間柒啤。

字符 ASCII Unicode UTF-8
'A' 0b01000001 0b00000000 01000001 0b01000001
'中' * 0b01001110 00101101 0b11100100 10111000 10101101

從上面的表格還可以發(fā)現(xiàn),UTF-8編碼有一個額外的好處棋枕,就是ASCII編碼實際上可以被看成是UTF-8編碼的一部分,所以妒峦,大量只支持ASCII編碼的歷史遺留軟件可以在UTF-8編碼下繼續(xù)工作重斑。

計算機(jī)系統(tǒng)中,通用的字符編碼工作方式:

  • 計算機(jī)內(nèi)存中肯骇,統(tǒng)一使用Unicode編碼
  • 計算機(jī)硬盤or需要傳輸的時候窥浪,轉(zhuǎn)換為UTF-8編碼
  • 用記事本編輯的時候祖很,從文件讀取的UTF-8字符被轉(zhuǎn)換為Unicode字符到內(nèi)存里,編輯完成后漾脂,保存的時候再把Unicode轉(zhuǎn)換為UTF-8保存到文件
  • 瀏覽網(wǎng)頁的時候假颇,服務(wù)器會把動態(tài)生成的Unicode內(nèi)容轉(zhuǎn)換為UTF-8再傳輸到瀏覽器,所以很多網(wǎng)頁的源碼上會有類似<meta charset="UTF-8" />的信息骨稿,表示該網(wǎng)頁正是用的UTF-8編碼笨鸡。

Python中的字符串

在最新的Python 3版本中,基本的str就是unicode:

python2

>>> print isinstance(str, unicode)
False
>>> print '包含中文的str'
包含中文的str
>>> print u'包含中文的str'
包含中文的str
>>> print isinstance('包含中文的str', unicode)
False
>>> print isinstance('包含中文的str', str)
True
>>> print isinstance(u'包含中文的str', unicode)
True
>>> print isinstance(u'包含中文的str', str)
False
>>> import chardet
>>> chardet.detect('包含中文的str')
{'confidence': 0.9690625, 'language': '', 'encoding': 'utf-8'}
>>> chardet.detect(u'包含中文的str')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/site-packages/chardet/__init__.py", line 34, in detect
    '{0}'.format(type(byte_str)))
TypeError: Expected object of type bytes or bytearray, got: <type 'unicode'>

在最新的Python 3版本中坦冠,基本的str就是unicode
python3

>>> # Py3中基本的str就是unicode形耗,所以可以直接判斷str
>>> print(isinstance(str, unicode))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'unicode' is not defined
>>> print('包含中文的str')
包含中文的str
>>> print(u'包含中文的str')
包含中文的str
>>> print(isinstance('包含中文的str', str))
True
>>> print(isinstance(u'包含中文的str', str))
True
>>> import chardet
>>> chardet.detect('包含中文的str' )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/site-packages/chardet/__init__.py", line 34, in detect
    '{0}'.format(type(byte_str)))
TypeError: Expected object of type bytes or bytearray, got: <class 'str'>
>>> chardet.detect(b'包含中文的str')
  File "<stdin>", line 1
SyntaxError: bytes can only contain ASCII literal characters.
>>> chardet.detect(u'包含中文的str')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/site-packages/chardet/__init__.py", line 34, in detect
    '{0}'.format(type(byte_str)))
TypeError: Expected object of type bytes or bytearray, got: <class 'str'>
>>>

字符的整數(shù)編碼

單個字符的unicode編碼可以用整數(shù)()表示
python3

>>> ord('A')
65
>>> chr(66)
'B'
>>> ord('中')
20013
>>> chr(25991)
'文'
>>> bin(20013)  # 字符'中'占了15位2進(jìn)制位
'0b100111000101101'
>>> oct(20013)  # 字符'中'占了5位8進(jìn)制位(1位8進(jìn)制位占3位2進(jìn)制位)
'0o47055'
>>> hex(20013)  # 字符'中'占了4位16進(jìn)制位(1位16進(jìn)制位占4位2進(jìn)制位)
'0x4e2d'
>>> bin(25991)  # 字符'文'占了15位2進(jìn)制位
'0b110010110000111'
>>> oct(25991)  # 字符'文'占了5位8進(jìn)制位(1位8進(jìn)制位占3位2進(jìn)制位)
'0o62607'
>>> hex(25991)  # 字符'文'占了4位16進(jìn)制位(1位16進(jìn)制位占4位2進(jìn)制位)
'0x6587'
>>> chr(20013)
'中'
>>> chr(0b100111000101101)
'中'
>>> chr(0o47055)
'中'
>>> chr(0x4e2d)
'中'
>>> chr(25991)
'文'
>>> chr(0b110010110000111)
'文'
>>> chr(0o62607)
'文'
>>> chr(0x6587)
'文'
* 用字符串orunicode編碼串寫法表示字符串完全是等價的

python3

>>> '\u4e2d'
'中'
>>> chr(0x4e2d)
'中'
>>> '中文'
'中文'
>>> '\u4e2d\u6587'
'中文'
* 將字符串strlist互相轉(zhuǎn)換
>>> ''.join( ['\u4e2d', '\u6587'] )
'中文'
>>> ''.join( [chr(0x4e2d), chr(0x6587)] )
'中文'
>>> list('中文')
['中', '文']
>>> list('\u4e2d\u6587')
['中', '文']

str(字符串)變?yōu)閎ytes(字節(jié)串)

由于Python的字符串類型是str,在內(nèi)存中以Unicode表示辙浑,一個字符對應(yīng)若干個字節(jié)激涤。如果要在網(wǎng)絡(luò)上傳輸,或者保存到磁盤上判呕,就需要把str變?yōu)橐宰止?jié)為單位的bytes倦踢。

python中的字符串有兩種存儲方式:

  • 一個字符一個字符的存儲
  • 一個Byte一個Byte的存儲

Python對bytes類型的數(shù)據(jù)用帶b前綴的單引號或雙引號表示:

>>> 'ABC'
'ABC'
>>> b'ABC'
b'ABC'

注意??區(qū)分'ABC'和b'ABC',前者是str侠草,后者雖然內(nèi)容顯示得和前者一樣辱挥,但bytes的每個字符都只占用一個字節(jié)。

* 把str轉(zhuǎn)化為Bytes
>>> 'ABC'.encode('ascii')
b'ABC'
>>> 'ABC'.encode('utf-8')
b'ABC'
>>> '中文'.encode('utf-8')
b'\xe4\xb8\xad\xe6\x96\x87'
>>> '中文'.encode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
  • 純英文的str可以用ASCII編碼為bytes梦抢,內(nèi)容是一樣的般贼,
  • 含有中文的str可以用UTF-8編碼為bytes。
  • 含有中文的str無法用ASCII編碼奥吩,因為中文編碼的范圍超過了ASCII編碼的范圍哼蛆,Python會報錯。
  • 雖說unicode編碼的每個字符占 2 Bytes霞赫,但是好像沒有辦法編碼到相應(yīng)的bytes
>>> len('ABC'.encode('ascii'))
3
>>> len('ABC'.encode('utf-8'))
3
>>> len('中文'.encode('utf-8'))
6
>>> list('中文'.encode('utf-8'))
[228, 184, 173, 230, 150, 135]
>>> len('中文str'.encode('utf-8'))
9
>>> list('中文str'.encode('utf-8'))
[228, 184, 173, 230, 150, 135, 115, 116, 114]
* 在bytes中腮介,無法顯示為ASCII字符的字節(jié),用\x##顯示

注意??
在unicode串中端衰,每個chr由\u4位16進(jìn)制編碼構(gòu)成叠洗,如字符'中'的unicode編碼為\u4e2d
在bytes串中,每個byte由\x2位16進(jìn)制編碼構(gòu)成旅东,如字符'中'的utf-8編碼轉(zhuǎn)換為bytes后為\xe4\xb8\xad

* 把Bytes變?yōu)?code>str

反過來灭抑,如果我們從網(wǎng)絡(luò)或磁盤上讀取了字節(jié)流,那么讀到的數(shù)據(jù)就是bytes抵代。要把bytes變?yōu)閟tr腾节,就需要用decode()方法:

>>> b'ABC'.decode('ascii')
'ABC'
>>> b'ABC'.decode('utf-8')
'ABC'
>>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
'中文'

注意??
如果bytes中包含無法解碼的byte,decode()方法會報錯;
如果bytes中只有一小部分無效的字節(jié)案腺,可以傳入errors='ignore'忽略錯誤的字節(jié)

>>> b'\xe4\xb8\xad\xff'.decode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 3: invalid start byte
>>> b'\xe4\xb8\xad\xff'.decode('utf-8', errors='ignore')
'中'
* 計算str包含多少個char庆冕,多少個byte

要計算str包含多少個字符,可以用len()函數(shù):

>>> len('ABC')
3
>>> len('中文')
2
>>> len('\u4e2d\u6587')
2
>>> len(b'ABC')
3
>>> len(b'\xe4\xb8\xad\xe6\x96\x87')
6
>>> len('中文'.encode('utf-8'))
6

可見
1個中文字符經(jīng)過UTF-8編碼后通常會占用3個字節(jié)劈榨,而1個英文字符只占用1個字節(jié)访递。
注意??
在操作字符串時,我們經(jīng)常遇到str和bytes的互相轉(zhuǎn)換同辣。為了避免亂碼問題拷姿,應(yīng)當(dāng)始終堅持使用UTF-8編碼對str(unicode)bytes進(jìn)行轉(zhuǎn)換。

Python源代碼

由于Python源代碼也是一個文本文件邑闺,所以跌前,當(dāng)你的源代碼中包含中文的時候,在保存源代碼時陡舅,就需要務(wù)必指定保存為UTF-8編碼抵乓。當(dāng)Python解釋器讀取源代碼時,為了讓它按UTF-8編碼讀取靶衍,我們通常在文件開頭寫上這兩行:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

第一行注釋是為了告訴Linux/OS X系統(tǒng)灾炭,這是一個Python可執(zhí)行程序,Windows系統(tǒng)會忽略這個注釋颅眶;

第二行注釋是為了告訴Python解釋器蜈出,按照UTF-8編碼讀取源代碼,否則涛酗,你在源代碼中寫的中文輸出可能會有亂碼铡原。

注意??
申明了UTF-8編碼并不意味著你的.py文件就是UTF-8編碼的,必須并且要確保文本編輯器正在使用UTF-8 without BOM編碼:

image.png

如果.py文件本身使用UTF-8編碼商叹,并且也申明了# -*- coding: utf-8 -*-燕刻,打開命令提示符測試就可以正常顯示中文:
image.png

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市剖笙,隨后出現(xiàn)的幾起案子卵洗,更是在濱河造成了極大的恐慌,老刑警劉巖弥咪,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件过蹂,死亡現(xiàn)場離奇詭異,居然都是意外死亡聚至,警方通過查閱死者的電腦和手機(jī)酷勺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來扳躬,“玉大人脆诉,你說我怎么就攤上這事勋功。” “怎么了库说?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長片择。 經(jīng)常有香客問我潜的,道長,這世上最難降的妖魔是什么字管? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任啰挪,我火速辦了婚禮,結(jié)果婚禮上嘲叔,老公的妹妹穿的比我還像新娘亡呵。我一直安慰自己,他們只是感情好硫戈,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布锰什。 她就那樣靜靜地躺著,像睡著了一般丁逝。 火紅的嫁衣襯著肌膚如雪汁胆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天霜幼,我揣著相機(jī)與錄音嫩码,去河邊找鬼。 笑死罪既,一個胖子當(dāng)著我的面吹牛铸题,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播琢感,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼丢间,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了猩谊?” 一聲冷哼從身側(cè)響起千劈,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎牌捷,沒想到半個月后墙牌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡暗甥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年喜滨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撤防。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡虽风,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情辜膝,我是刑警寧澤无牵,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站厂抖,受9級特大地震影響茎毁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜忱辅,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一七蜘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧墙懂,春花似錦橡卤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至巧勤,卻和暖如春谈为,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背踢关。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工伞鲫, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人签舞。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓秕脓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親儒搭。 傳聞我的和親對象是個殘疾皇子吠架,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355

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

  • 背景知識 ASCII編碼: 最早的計算機(jī)在設(shè)計時采用8個bit作為1個Byte,所以搂鲫,一個字節(jié)能表示的最大的整數(shù)就...
    emm_simon閱讀 340評論 0 0
  • 字符集和編碼簡介 在編程中常嘲可以見到各種字符集和編碼,包括ASCII,MBCS,Unicode等字符集魂仍。確切的說...
    蘭山小亭閱讀 8,494評論 0 13
  • 說明:本文是我在readthedocs看到的拐辽,覺得很不錯所以轉(zhuǎn)載過來,有刪改擦酌,原文地址點這里俱诸。 實用Unicode...
    aurora閱讀 981評論 0 6
  • 1、字符串編碼 字符串也是一種數(shù)據(jù)類型赊舶,但是睁搭,字符串比較特殊的是還有一個編碼問題赶诊。 因為計算機(jī)只能處理數(shù)字,如果要...
    Hello密斯托李閱讀 355評論 0 0
  • 字符串和編碼 因為計算機(jī)只能處理數(shù)字园骆,如果要處理文本舔痪,就必須先把文本轉(zhuǎn)換為數(shù)字才能處理。最早的計算機(jī)在設(shè)計時采用8...