Python的字符串編碼規(guī)則一直讓我很頭疼,花了點(diǎn)時(shí)間研究了下,并不復(fù)雜。主要涉及的內(nèi)容有常用的字符編碼的特點(diǎn),并介紹了在python2.x中如何與編碼問題作戰(zhàn),本文關(guān)于Python的內(nèi)容僅適用于2.x,3.x中str和unicode有翻天覆地的變化,具體請(qǐng)查閱相關(guān)資料。
1. 字符編碼簡(jiǎn)介
1.1. ASCII
ASCII(American Standard Code for Information Interchange),是一種單字節(jié)的編碼。計(jì)算機(jī)世界里一開始只有英文,而單字節(jié)可以表示256個(gè)不同的字符,可以表示所有的英文字符和許多的控制符號(hào)。不過ASCII只用到了其中的一半(/x80以下),這也是MBCS得以實(shí)現(xiàn)的基礎(chǔ)。
1.2. MBCS
然而計(jì)算機(jī)世界里很快就有了其他語言,單字節(jié)的ASCII已無法滿足需求。后來每個(gè)語言就制定了一套自己的編碼,由于單字節(jié)能表示的字符太少,而且同時(shí)也需要與ASCII編碼保持兼容,所以這些編碼紛紛使用了多字節(jié)來表示字符,如GBxxx、BIGxxx等等,他們的規(guī)則是,如果第一個(gè)字節(jié)是/x80以下,則仍然表示ASCII字符;而如果是/x80以上,則跟下一個(gè)字節(jié)一起(共兩個(gè)字節(jié))表示一個(gè)字符,然后跳過下一個(gè)字節(jié),繼續(xù)往下判斷。
這里,IBM發(fā)明了一個(gè)叫Code Page的概念,將這些編碼都收入囊中并分配頁碼,GBK是第936頁,也就是CP936。所以,也可以使用CP936表示GBK。
MBCS(Multi-Byte Character Set)是這些編碼的統(tǒng)稱。目前為止大家都是用了雙字節(jié),所以有時(shí)候也叫做DBCS(Double-Byte Character Set)。必須明確的是,MBCS并不是某一種特定的編碼,Windows里根據(jù)你設(shè)定的區(qū)域不同,MBCS指代不同的編碼,而Linux里無法使用MBCS作為編碼。在Windows中你看不到MBCS這幾個(gè)字符,因?yàn)槲④洖榱烁友髿猓褂昧薃NSI來嚇唬人,記事本的另存為對(duì)話框里編碼ANSI就是MBCS。同時(shí),在簡(jiǎn)體中文Windows默認(rèn)的區(qū)域設(shè)定里,指代GBK。
1.3. Unicode
后來,有人開始覺得太多編碼導(dǎo)致世界變得過于復(fù)雜了,讓人腦袋疼,于是大家坐在一起拍腦袋想出來一個(gè)方法:所有語言的字符都用同一種字符集來表示,這就是Unicode。
最初的Unicode標(biāo)準(zhǔn)UCS-2使用兩個(gè)字節(jié)表示一個(gè)字符,所以你常常可以聽到Unicode使用兩個(gè)字節(jié)表示一個(gè)字符的說法。但過了不久有人覺得256*256太少了,還是不夠用,于是出現(xiàn)了UCS-4標(biāo)準(zhǔn),它使用4個(gè)字節(jié)表示一個(gè)字符,不過我們用的最多的仍然是UCS-2。
UCS(Unicode Character Set)還僅僅是字符對(duì)應(yīng)碼位的一張表而已,比如"漢"這個(gè)字的碼位是6C49。字符具體如何傳輸和儲(chǔ)存則是由UTF(UCS Transformation Format)來負(fù)責(zé)。
一開始這事很簡(jiǎn)單,直接使用UCS的碼位來保存,這就是UTF-16,比如,"漢"直接使用/x6C/x49保存(UTF-16-BE),或是倒過來使用/x49/x6C保存(UTF-16-LE)。但用著用著美國(guó)人覺得自己吃了大虧,以前英文字母只需要一個(gè)字節(jié)就能保存了,現(xiàn)在大鍋飯一吃變成了兩個(gè)字節(jié),空間消耗大了一倍……于是UTF-8橫空出世。
UTF-8是一種很別扭的編碼,具體表現(xiàn)在他是變長(zhǎng)的,并且兼容ASCII,ASCII字符使用1字節(jié)表示。然而這里省了的必定是從別的地方摳出來的,你肯定也聽說過UTF-8里中文字符使用3個(gè)字節(jié)來保存吧?4個(gè)字節(jié)保存的字符更是在淚奔……(具體UCS-2是怎么變成UTF-8的請(qǐng)自行搜索)
另外值得一提的是BOM(Byte Order Mark)。我們?cè)趦?chǔ)存文件時(shí),文件使用的編碼并沒有保存,打開時(shí)則需要我們記住原先保存時(shí)使用的編碼并使用這個(gè)編碼打開,這樣一來就產(chǎn)生了許多麻煩。(你可能想說記事本打開文件時(shí)并沒有讓選編碼?不妨先打開記事本再使用文件 -> 打開看看)而UTF則引入了BOM來表示自身編碼,如果一開始讀入的幾個(gè)字節(jié)是其中之一,則代表接下來要讀取的文字使用的編碼是相應(yīng)的編碼:
BOM_UTF8 '/xef/xbb/xbf'
BOM_UTF16_LE '/xff/xfe'
BOM_UTF16_BE '/xfe/xff'
并不是所有的編輯器都會(huì)寫入BOM,但即使沒有BOM,Unicode還是可以讀取的,只是像MBCS的編碼一樣,需要另行指定具體的編碼,否則解碼將會(huì)失敗。
你可能聽說過UTF-8不需要BOM,這種說法是不對(duì)的,只是絕大多數(shù)編輯器在沒有BOM時(shí)都是以UTF-8作為默認(rèn)編碼讀取。即使是保存時(shí)默認(rèn)使用ANSI(MBCS)的記事本,在讀取文件時(shí)也是先使用UTF-8測(cè)試編碼,如果可以成功解碼,則使用UTF-8解碼。記事本這個(gè)別扭的做法造成了一個(gè)BUG:如果你新建文本文件并輸入"姹 主站蜘蛛池模板: 西充县| 繁昌县| 和田市| 时尚| 亳州市| 宾阳县| 沂源县| 绥江县| 南京市| 滁州市| 元朗区| 黄浦区| 清苑县| 宁波市| 兰坪| 胶州市| 长顺县| 三河市| 合肥市| 镇赉县| 曲阜市| 兴业县| 衡南县| 嵩明县| 漳平市| 都兰县| 蕉岭县| 涞源县| 新建县| 大新县| 留坝县| 淳安县| 合阳县| 汝南县| 鹤山市| 潼南县| 巴南区| 富锦市| 凤山市| 锡林浩特市| 鹿邑县|