字符編碼
字符串相對于其他數(shù)據(jù)類型有一個特殊的地方:就是編碼問題。
我們知道計算機只能處理數(shù)字般婆,所以要讓它能夠處理文本就需要將文本用對應的數(shù)字來表示才能處理。所以美國人一開始設(shè)計出了ASCII編碼朵逝,只有127個字符被編碼到計算機里蔚袍,也就是大小寫英文字母、數(shù)字和一些符號配名。但是用一個字節(jié)來處理中文遠遠不夠啤咽,至少需要兩個字節(jié),中國人只好自己制定了GB2312編碼來處理漢字渠脉。由于GB2312編碼能夠處理的漢字也有限宇整,微軟又在GB2312編碼基礎(chǔ)上制定GBK編碼。隨后中國制定出了GB10803編碼连舍,與GB2312完全兼容,與GBK基本兼容涩哟,支持Unicode的全部統(tǒng)一漢字索赏,共收錄漢字70244個。GB 18030主要有以下特點:
- 與UTF-8相同贴彼,采用多字節(jié)編碼潜腻,每個字可以由1個、2個或4個字節(jié)組成器仗。
- 編碼空間龐大融涣,最多可定義161萬個字符。
- 支持中國國內(nèi)少數(shù)民族的文字精钮,不需要動用造字區(qū)威鹿。
- 漢字收錄范圍包含繁體漢字以及日韓漢字。
像天朝一樣轨香,當計算機傳到世界各個國家時忽你,為了適合當?shù)卣Z言和字符,設(shè)計和實現(xiàn)類似GB2312/GBK/GB18030的編碼方案臂容。這樣各搞一套科雳,在本地使用沒有問題根蟹,一旦出現(xiàn)在網(wǎng)絡(luò)中,由于不兼容糟秘,互相訪問就出現(xiàn)了亂碼現(xiàn)象简逮。 為了能夠處理各國的文字,由此Unicode(萬國碼尿赚,統(tǒng)一碼散庶,單一碼,標準萬國碼)編碼應運而生吼畏,Unicode編碼系統(tǒng)為表達任意語言的任意字符而設(shè)計督赤。它使用4字節(jié)的數(shù)字來表達每個字母、符號泻蚊,或者表意文字躲舌。
統(tǒng)一成Unicode編碼,亂碼問題從此消失了性雄。但是没卸,如果你寫的文本基本上全部是英文的話,用Unicode編碼比ASCII編碼需要多一倍的存儲空間秒旋,在存儲和傳輸上就十分不劃算约计。人們又想出了把Unicode編碼轉(zhuǎn)化為“可變長編碼”的UTF-8編碼。
UTF-8使用一至四個字節(jié)為每個字符編碼迁筛,UTF-8是ASCII的一個超集煤蚌。因為一個純ASCII字符串也是一個合法的UTF-8字符串,所以現(xiàn)存的ASCII文本不需要轉(zhuǎn)換细卧。
Python字符串
幾個常用關(guān)于字符串的函數(shù):
- ord():獲取字符的整數(shù)表示尉桩。
>>> ord('b')
98
>>> ord('字')
23383
- chr():把編碼轉(zhuǎn)換為對應的字符。
>>> chr(99)
'c'
>>> chr(23384)
'存'
- encode():將字符串編碼為指定的bytes贪庙。
encode()函數(shù).png
純英文的str可以用ASCII編碼為bytes蜘犁,內(nèi)容是一樣的,含有中文的str可以用UTF-8編碼為bytes止邮。含有中文的str無法用ASCII編碼这橙,因為中文編碼的范圍超過了ASCII編碼的范圍,Python會報錯导披。在bytes中屈扎,無法顯示為ASCII字符的字節(jié),用\x##顯示撩匕。
- decode():若我們從網(wǎng)絡(luò)或磁盤上讀取了字節(jié)流助隧,那么獲得的數(shù)據(jù)就是bytes。要把bytes變?yōu)閟tr,就需要用到decode()方法并村。
decode()函數(shù).png
如果bytes中包含無法解碼的字節(jié)巍实,decode()方法會報錯:
decode()函數(shù)報錯.png
如果bytes中只有一小部分無效的字節(jié),可以傳入errors='ignore'忽略錯誤的字節(jié):
ignore.png
- len():計算str的字符數(shù)哩牍,如果換成bytes棚潦,len()函數(shù)就計算字節(jié)數(shù)。
len()函數(shù).png
通過len()的計算我們發(fā)現(xiàn):1個中文字符經(jīng)過UTF-8編碼后通常會占用3個字節(jié)膝昆,而1個英文字符只占用1個字節(jié)丸边。
在字符串處理中,我們會經(jīng)常遇到str和bytes的互相轉(zhuǎn)換荚孵。為了避免亂碼問題妹窖,應當堅持使用UTF-8編碼對str和bytes進行轉(zhuǎn)換的好習慣。
由于Python源代碼也是一個文本文件收叶,當我們的源代碼中包含中文的時候骄呼,如果不用指定的編碼保存源代碼,當Python解釋器讀取源代碼時判没,展現(xiàn)在我們眼前的就可能是亂碼蜓萄。所以我們務(wù)必要用UTF-8編碼保存源代碼,當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編碼:
文本編輯器.png
如果.py文件本身使用UTF-8編碼玻佩,并且也申明了# -- coding: utf-8 --,打開命令提示符測試就可以正常顯示中文:
顯示中文.png
字符串的格式化
最后一個常見的問題是如何輸出格式化的字符串漱牵。我們經(jīng)常會輸出類似'x年x班的xxx夺蛇,今年xx歲疚漆,數(shù)學期末成績是xx'之類的字符串酣胀,而xxx的內(nèi)容都是根據(jù)變量變化的,所以娶聘,需要一種簡便的格式化字符串的方式闻镶。
在Python中,采用的格式化方式和C語言是一致的丸升,用%實現(xiàn)铆农,舉例如下:
格式化.png
%運算符就是用來格式化字符串的。在字符串內(nèi)部,%s表示用字符串替換墩剖,%d表示用整數(shù)替換猴凹,有幾個%?占位符,后面就跟幾個變量或者值岭皂,順序要對應好郊霎。如果只有一個%?,括號可以省略爷绘。
常見的占位符有:
占位符 | 替換內(nèi)容 |
---|---|
%d | 整數(shù) |
%f | 浮點數(shù) |
%s | 字符串 |
%x | 十六進制整數(shù) |
其中书劝,格式化整數(shù)和浮點數(shù)還可以指定是否補0和整數(shù)與小數(shù)的位數(shù):
# -*- coding: utf-8 -*-
print('%2d-%02d' % (3, 1))
print('%.2f' % 3.1415926)
如果你不太確定應該用什么,%s永遠起作用土至,它會把任何數(shù)據(jù)類型轉(zhuǎn)換為字符串:
>>> 'Age: %s. Gender: %s' % (25, True)
'Age: 25. Gender: True'
有些時候购对,字符串里面的%是一個普通字符怎么辦?這個時候就需要轉(zhuǎn)義陶因,用%%來表示一個%:
>>> 'growth rate: %d %%' % 7
'growth rate: 7 %'
- format()
另一種格式化字符串的方法是使用字符串的format()方法骡苞,它會用傳入的參數(shù)依次替換字符串內(nèi)的占位符{0}、{1}……坑赡,不過這種方式寫起來比%要麻煩得多:
>>> 'Hello, {0}, 成績提升了 {1:.1f}%'.format('小明', 17.125)
'Hello, 小明, 成績提升了 17.1%'
小結(jié)
Python 3的字符串使用Unicode烙如,直接支持多語言。
當str和bytes互相轉(zhuǎn)換時毅否,需要指定編碼亚铁。最常用的編碼是UTF-8。Python當然也支持其他編碼方式螟加,比如把Unicode編碼成GB2312:
>>> '中文'.encode('gb2312')
b'\xd6\xd0\xce\xc4'
但這種方式純屬自找麻煩徘溢,如果沒有特殊業(yè)務(wù)要求,請牢記僅使用UTF-8編碼捆探。
格式化字符串的時候然爆,可以用Python的交互式環(huán)境測試,方便快捷黍图。