概覽
????"string"的概念很簡單鹿鳖,就是字符的序列俄讹。但是怎么定義字符是一個問題篮洁。在python3帽芽,str是由Unicode字符組成删掀,而在python2里str是由原始的byte字符組成。
????Unicode標準把字符的標識和字符的二進制表示區(qū)分開來:
- 字符的標識导街,即碼位(code point)披泪,是一個從0到1,114,111的數(shù)字,在Unicode標準里是以U+為前綴的4到6位的16進制數(shù)字搬瑰。如字母A的碼位是U+0041款票。
- 實際的一個字符的二進制表示是由具體使用的編碼(encoding)決定。如字母A在UTF-8編碼里是單個字節(jié)\x41而在UTF-16LE編碼下是兩個字節(jié)\x41\x00泽论。
????從碼位轉(zhuǎn)換字節(jié)是encoding艾少,從字節(jié)轉(zhuǎn)換到碼位是decoding。
字符編碼的各式各樣的問題
????本章后面講了很多因為字符編碼產(chǎn)生的問題佩厚,在目前做過的項目中基本沒碰到過姆钉,感覺主要出現(xiàn)在像希臘語,葡萄牙語還有泰米爾語這類語言上,也沒去深入研究潮瓶,簡單做下總結(jié)陶冷。
- 有些編碼包含的字符只是Unicode的一個子集,當把一個Unicode字符轉(zhuǎn)換到目標編碼時毯辅,如果目標編碼不包含這個字符的定義埂伦,則會報UnicodeEncodeError,可以通過在
encode
方法中加入error參數(shù)思恐,對錯誤進行忽略或者做一些處理沾谜。 - 如果二進制編碼有錯,不是一個有效的編碼胀莹,則在把二進制編碼轉(zhuǎn)換到Unicode字符時基跑,會報UnicodeDecodeError,也可以通過在decode方法中加入error參數(shù)描焰,對錯誤進行忽略或者做一些處理媳否。
- 從python3開始,源碼的默認編碼采用UTF-8荆秦,而python2的默認編碼是ASCII篱竭,意味著
#!coding: utf8
不需要再加了。 - 作者討論了下是不是能從二進制序列里發(fā)現(xiàn)編碼方式步绸,答案是不可以掺逼。但是可以通過一些特殊的規(guī)則大概確定一下,作者介紹了個chardet的項目瓤介。
- BOM是用來標識大端序和小端序的吕喘,對于UTF-16是需要的,但是對于UTF-8不是必須的惑朦,python沒有使用BOM來判斷一個文件是否是UTF-8兽泄。
- 如果使用python默認的編碼漓概,可能會出問題漾月,比如用UTF-8編碼寫一個文件,但是讀的時候沒指定編碼胃珍,在Linux上沒問題梁肿,但是可能在Windows上就有問題。最好是在所有的操作上都明確指定編碼格式觅彰。
- 因為組合字符的原因吩蔑,字符串比較會有些問題,打印出來是一樣的字符填抬,可能實際的編碼不一樣烛芬,python提供了一些normalize方法進行歸一化,不過作者也提到像google就是直接把這些變音符給去掉。
- 在字符串排序時有可能也會出現(xiàn)問題赘娄,作者推薦了個PyUCA仆潮。
- python中有一個完整的Unicode database,記錄了每個字符的各方面的信息遣臼。
- python的接口可以支持str和bytes的輸入?yún)?shù)性置,但是根據(jù)參數(shù)類型不同,結(jié)果也不同揍堰。
- python提供了struct模塊去對打包在一起的bytes進行拆包鹏浅。
>>> import struct
>>> fmt = '<3s3sHH' #
>>> with open('filter.gif', 'rb') as fp: ... img = memoryview(fp.read()) # ...
>>> header = img[:10] #
>>> bytes(header) # b'GIF89a+\x02\xe6\x00'
>>> struct.unpack(fmt, header) # (b'GIF', b'89a', 555, 230)
>>> del header #
>>> del img