總結下編碼問題的相關概念。
字符集和編碼的區別
字符集(Character Set)是字符的集合,即爲每一個字符分配一個唯一的ID(碼點,Code Point)。
編碼(Encoding)是把碼點轉化爲字節序列的規則。因爲在實際存儲中不一定是直接存儲字符的碼點(比如爲了節約空間),所以需要一種轉換規則,這種規則就是編碼。
ASCII,GB2312,GBK都是字符集,同時它們也代表了對應的編碼方式(不嚴格區分)。
Unicode是一種字符集,但它的編碼方式有多種,如utf-8和utf-16。
各種字符集和編碼
ASCII:儲存所有英文字符和部分符號,由0~127表示,每個字符爲1字節。
GB2312:是
ASCII
碼的中文擴展,小於127的字節與原來相同,而用兩個大於127的字節來表示中文,加入了大約7000個漢字。同時把ASCII
碼中的原有字符重新編GBK:是對
gb2312
的擴展,規定只要高字節大於127則就表示這是一個漢字的開始,從而又增加了20000多個漢字。後來又加入幾千個少數民族的字,擴展爲GB18030
。ANSI:不同國家制定了不同標準,包括美國的
ASCII
,中國的GBK
,日本的Shift_JIS
,韓國的Euc-kr
等。這些不同國家的編碼標準合稱爲ANSI
編碼。不同的ANSI
編碼之間互不兼容,對於簡體中文系統,ANSI
編碼就等同於GBK
編碼。Unicode:是一套字符集,包括了世界上所有的文字和符號。總空間爲17個平面(0x0000~0x10ffff),最常用的0號平面(MBP)包含65535個碼點,以2個字節表示。
UTF-8:是
unicode
的一種編碼方式,將一個碼位編碼成1~4字節。
對於單字節的字符,字節的第一位設爲0,與ASCII
碼相同;而對於n個字節的字符(n>1),第一個字節的前n位設爲1,第n+1位設爲0,後面字節的前兩位都設爲10,其餘空位由低到高地填充該字符unicode碼,高位用0補足。
UTF-8
編碼將英文字符編碼爲1字節,將漢字一般編碼爲3字節,相比直接存儲unicode
碼點節約了空間。U+ 0000 ~ U+ 007F: 0XXXXXXX U+ 0080 ~ U+ 07FF: 110XXXXX 10XXXXXX U+ 0800 ~ U+ FFFF: 1110XXXX 10XXXXXX 10XXXXXX U+10000 ~ U+1FFFF: 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
- Windows默認使用GBK編碼,而Linux系統默認使用UTF-8編碼,不同系統間文件傳輸時需進行轉碼。
Python編碼問題
在Python內部,字符串(str)以
unicode
形式存在,即每一個字符存在對應的唯一的編號,ord(str)
可以獲取該編號(即爲碼點),chr(codepoint)
可以獲取編號對應的字符。>>> ord('a') 97 >>> ord('中') 20013 >>> chr(20013) '中' >>> '\u4e2d' '中'
編碼和解碼
Python的字符串(str)在內存中以Unicode
形式存在,如果需要在網絡中傳輸或是存儲在硬盤中,則要通過encode()
編碼成字節流(bytes)。同樣,從網絡或磁盤中讀取到的字節流可以通過decode()
解碼成字符串。>>> 'ABC'.encode('ascii') b'ABC' >>> '中文'.encode('utf-8') b'\xe4\xb8\xad\xe6\x96\x87' >>> '中文'.encode('gb2312') b'\xd6\xd0\xce\xc4' >>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8') '中文'
- 文件IO的編碼問題
Python可以使用open()
打開文件,接收參數依次爲文件路徑,打開方式(r/w),編碼方式(encoding)。
如果是讀取文件,則encoding
參數指定的是將文件內容解碼(decode)爲字符串str(unicode)所用的編碼方式,此時encoding
應與文件編碼保持一致。
如果是寫入文件,則encoding
指定的是將字符串(unicode)編碼(encode)並存儲於文件所用的編碼方式。
Python中打開文件,如果不指定encoding
參數,則默認使用cp936
,也就是我們熟悉的GBK
編碼。