楔子 這一次我們分析一下Python的字符串,首先字符串是一個(gè)變長對(duì)象,,因?yàn)椴煌L度的字符串所占的內(nèi)存是不一樣的,;但同時(shí)字符串又是一個(gè)不可變對(duì)象,,因?yàn)橐坏﹦?chuàng)建就不可以再修改了。 而Python中的字符串是通過unicode來表示的,,在底層對(duì)應(yīng)的結(jié)構(gòu)體是PyUnicodeObject,。不過話說回來,為什么需要unicode呢? 首先計(jì)算機(jī)存儲(chǔ)的基本單位是字節(jié),,由8個(gè)比特位組成,,由于英文字母算上大小寫只有52個(gè),再加上若干字符,,數(shù)量不會(huì)超過256個(gè),因此一個(gè)字節(jié)完全可以表示,。但是隨著計(jì)算機(jī)的普及,,越來越多的非英文字符出現(xiàn),導(dǎo)致一個(gè)字節(jié)已經(jīng)無法表示了,。所以只能曲線救國,,對(duì)于一個(gè)字節(jié)無法表示的字符,使用多個(gè)字節(jié)表示,。 但是這樣會(huì)出現(xiàn)兩個(gè)問題:
到這里我們先不繼續(xù)往下深入,,我們先來理清楚一些概念,。 字符集和字符編碼 估計(jì)有很多小伙伴搞不清這兩者的區(qū)別,我們先來解釋一下所謂的字符集和字符編碼是怎么一回事,? 字符集:系統(tǒng)支持的所有字符組成的集合,,像ASCII、GB2312,、Big5,、unicode都屬于字符集。只不過不同的字符集所能容納的字符個(gè)數(shù)不同,,比如ASCII字符集中不包含中文,,unicode則可以容納世界上的所有字符; 字符編碼:負(fù)責(zé)將每個(gè)字符轉(zhuǎn)換成一個(gè)或多個(gè)計(jì)算機(jī)可以接受的具體數(shù)字,,該數(shù)字可以理解為編號(hào),,因此字符編碼維護(hù)了字符和編號(hào)之間的對(duì)應(yīng)關(guān)系,。而編碼也分為多種,比如ascii,、gbk,、utf-8等等,字符編碼不同,,那么字符轉(zhuǎn)換之后的編號(hào)也不同,,當(dāng)然能轉(zhuǎn)化的字符種類也不同。比如ASCII這種字符編碼,,它就只能轉(zhuǎn)換ASCII字符,。
將字符串中的每一個(gè)字符轉(zhuǎn)成對(duì)應(yīng)的編號(hào),那么得到的就是字節(jié)序列(bytes對(duì)象),,因?yàn)橛?jì)算機(jī)存儲(chǔ)和網(wǎng)絡(luò)通訊的基本單位都是字節(jié),,所以字符串必須以字節(jié)序列的形式進(jìn)行存儲(chǔ)或傳輸。 因此字符串和字節(jié)序列在某種程度上是很相似的,,字符串按照指定的編碼進(jìn)行encode即可得到字節(jié)序列,,也就是將每個(gè)字符都轉(zhuǎn)成對(duì)應(yīng)的編號(hào);字節(jié)序列按照相同的編碼decode即可得到字符串,,也就是根據(jù)編號(hào)找到對(duì)應(yīng)的字符,。 比如我們寫了一段文本,然后在存儲(chǔ)的時(shí)候必須先進(jìn)行編碼,,也就是將每一個(gè)字符都轉(zhuǎn)成一個(gè)或多個(gè)系統(tǒng)可以接受的數(shù)字,、即對(duì)應(yīng)的編號(hào)之后,才可以進(jìn)行存儲(chǔ),。
假設(shè)文本中只有你好二字,,在存儲(chǔ)的時(shí)候采用gbk進(jìn)行編碼,那么在讀取的時(shí)候也必須使用gbk進(jìn)行解碼,,否則的話就會(huì)無法解析而報(bào)錯(cuò),。因?yàn)樽址幋a不同,字符對(duì)應(yīng)的編號(hào)也不同,。 再比如每個(gè)國家都有自己的字符編碼,,你在日本的一臺(tái)計(jì)算機(jī)上寫好的文件拿到中國的計(jì)算機(jī)上打開,很有可能出現(xiàn)亂碼。因?yàn)樽址幋a不同,,字符和編號(hào)之間的對(duì)應(yīng)關(guān)系也不同,,采用不同的字符編碼進(jìn)行解析肯定會(huì)出問題。 但我們說,,對(duì)于ASCII字符來說,,由于不管采用哪一種編碼,它們得到的編號(hào)都是固定的,。所以編碼對(duì)于ASCII字符來說,,沒有任何影響。
這里我們?cè)倩貞浺幌耣ytes對(duì)象,我們創(chuàng)建的時(shí)候可以采用字面量的方式,,比如 b"abc",,但是 b"憨"卻不可以。原因就是憨這個(gè)字符不是ASCII字符,,那么采用不同的字符編碼,其對(duì)應(yīng)的編號(hào)是不同的,,而這種方式Python又不知道我們使用哪一種編碼,,所以不允許這么做,而是需要通過"憨".encode的方式手動(dòng)指定字符編碼,。 但是對(duì)于 ASCII 字符而言,,不管采用哪一種字符編碼,得到的編號(hào)都是一樣的,, 所以Python針對(duì)ASCII字符則允許這種做法,,比如b"abc"。并且我們看到,,對(duì)于漢字來說,,在編碼之后會(huì)對(duì)應(yīng)多個(gè)編號(hào),而每個(gè)編號(hào)占1字節(jié),,因此不同的字符所占的大小可能不同,。 小結(jié) 以上就是字符集和字符編碼,字符集就是字符組成的集合,,不同字符集所能容納的字符數(shù)量是有限的,。字符編碼是將字符轉(zhuǎn)成對(duì)應(yīng)的編號(hào),比如將一個(gè)字符串中的所有字符都轉(zhuǎn)成對(duì)應(yīng)的編號(hào)之后,,就得到了字節(jié)序列,。 當(dāng)然和字符集一樣,字符編碼能轉(zhuǎn)換的字符種類也是有限的,像漢字我們可以使用 gbk 編碼,、utf-8 編碼,,但是不能使用 ascii 編碼。 以上算是理清楚了一些概念,,顯然過于簡單了,,主要是為后面的內(nèi)容做鋪墊。那么下一篇,,就來從Python的角度分析字符串的存儲(chǔ)方式,。 |
|