最近在用python寫多語言的一個插件時,涉及到python3.x中的unicode和編碼操做,本文就是針對編碼問題研究的彙總,目前已開源至github。如下內容來自項目中的README。html
1.1 ASCIIpython
美國信息交換標準碼。 在計算機的存儲單元中,一個ASCII碼值佔一個字節(8個二進制位),但其最高位(b7)用做奇偶校驗位。ASCII(American Standard Code for Information Interchange),是一種單字節的編碼。計算機世界裏一開始只有英文,而單字節能夠表示256個不一樣的字符,能夠表示全部的英文字符和許多的控制符號。不過ASCII只用到了其中的一半(\x80如下),這也是MBCS得以實現的基礎。git
1.2 ISO8859-一、EASCIIgithub
EASCII是ASCII的擴充,把第八位也用來存儲信息;在Windows中用Alt+小鍵盤數字輸入的就是EASCII碼對應字符。ISO8859-1就是EASCII最典型的實現,基本可以覆蓋西歐的拉丁字母,因此又叫Latin-1。有些國外程序就要求使用ISO8859-1編碼以保證Binary Safe,好比著名的XMB。python3.x
1.3 Unicode、UTF-8app
Unicode是業界的一種標準,它可使電腦得以呈現世界上數十種文字的系統。 後來,有人開始以爲太多編碼致使世界變得過於複雜了,讓人腦殼疼,因而你們坐在一塊兒拍腦殼想出來一個方法:全部語言的字符都用同一種字符集來表示,這就是Unicode。函數
最初的Unicode標準UCS-2使用兩個字節表示一個字符,因此你經常能夠聽到Unicode使用兩個字節表示一個字符的說法。但過了不久有人以爲256*256太少了,仍是不夠用,因而出現了UCS-4標準,它使用4個字節表示一個字符,不過咱們用的最多的仍然是UCS-2。編碼
UCS(Unicode Character Set)還僅僅是字符對應碼位的一張表而已,好比"漢"這個字的碼位是6C49。字符具體如何傳輸和儲存則是由UTF(UCS Transformation Format)來負責。操作系統
一開始這事很簡單,直接使用UCS的碼位來保存,這就是UTF-16,好比,"漢"直接使用\x6C\x49保存(UTF-16-BE),或是倒過來使用\x49\x6C保存(UTF-16-LE)。但用着用着美國人以爲本身吃了大虧,之前英文字母只須要一個字節就能保存了,如今大鍋飯一吃變成了兩個字節,空間消耗大了一倍……因而UTF-8橫空出世。插件
UTF-8是一種很彆扭的編碼,具體表如今他是變長的,而且兼容ASCII,ASCII字符使用1字節表示。然而這裏省了的一定是從別的地方摳出來的,你確定也據說過UTF-8裏中文字符使用3個字節來保存吧?4個字節保存的字符更是在淚奔……(具體UCS-2是怎麼變成UTF-8的請自行搜索) Unicode的實現方式不一樣於編碼方式,一個字符的Unicode編碼是肯定的,可是在實際傳輸過程當中,因爲不一樣系統平臺的設計不必定一致,以及出於節省空間的目的,對Unicode編碼的實現方式有所不一樣。因而就有了UTF-八、UTF-1六、UTF-32。
UTF-8使用一至四個字節爲每一個字符編碼:
ASCII字符只需一個字節編碼(Unicode範圍由U+0000至U+007F)。帶有附加符號的拉丁文、希臘文、西裏爾字母、亞美尼亞語、希伯來文、阿拉伯文、敘利亞文及它拿字母(即以ISO 8859爲主的)則須要二個字節編碼(Unicode範圍由U+0080至U+07FF)。其餘基本多文種平面(BMP)中的字符(這包含了大部分經常使用字,包括漢字)使用三個字節編碼。其餘極少使用的Unicode 輔助平面的字符使用四字節編碼。它惟一的好處在於兼容ASCII。 UTF-16則是以U+10000爲分界線,使用兩個字節或者四個字節存儲。 UTF-32則是所有使用4字節編碼,很浪費空間。
1.4 GB23十二、GBK、GB18030
GB是中國荒謬的國家標準。GB23十二、GBK、GB18030各爲前一個的擴展。
我歷來討厭GB編碼,由於它毫無國際兼容性。更荒謬的是,GBK和GB18030幾乎是照着Unicode字符集選取的字庫。這樣畫蛇添足地弄出一套編碼,還強制全部在中國銷售的操做系統必須使用它,真是天朝特點。
另外,對於GB編碼PHP是不認帳的,mb_detect_encoding函數會把GB編碼識別成CP936。
1.5 MSCS
然而計算機世界裏很快就有了其餘語言,單字節的ASCII已沒法知足需求。後來每一個語言就制定了一套本身的編碼,因爲單字節能表示的字符太少,並且同時也須要與ASCII編碼保持兼容,因此這些編碼紛紛使用了多字節來表示字符,如GBxxx、BIGxxx等等,他們的規則是,若是第一個字節是\x80如下,則仍然表示ASCII字符;而若是是\x80以上,則跟下一個字節一塊兒(共兩個字節)表示一個字符,而後跳過下一個字節,繼續往下判斷。
這裏,IBM發明了一個叫Code Page的概念,將這些編碼都收入囊中並分配頁碼,GBK是第936頁,也就是CP936。因此,也可使用CP936表示GBK。
MBCS(Multi-Byte Character Set)是這些編碼的統稱。目前爲止你們都是用了雙字節,因此有時候也叫作DBCS(Double-Byte Character Set)。必須明確的是,MBCS並非某一種特定的編碼,Windows里根據你設定的區域不一樣,MBCS指代不一樣的編碼,而Linux裏沒法使用MBCS做爲編碼。在Windows中你看不到MBCS這幾個字符,由於微軟爲了更加洋氣,使用了ANSI來嚇唬人,記事本的另存爲對話框裏編碼ANSI就是MBCS。同時,在簡體中文Windows默認的區域設定裏,指代GBK。
open狀態rb對應的是_io.BufferedReader,r對應的是_io.TextIOWrapper
class io.TextIOWrapper(buffer, encoding=None, errors=None, newline=None, line_buffering=False)
A buffered text stream over a BufferedIOBase binary stream. It inherits TextIOBase. encoding gives the name of the encoding that the stream will be decoded or encoded with. It defaults to locale.getpreferredencoding().
字符串在Python內部的表示是unicode編碼,所以,在作編碼轉換時,一般須要以unicode做爲中間編碼,即先將其餘編碼的字符串解碼(decode)成unicode,再從unicode編碼(encode)成另外一種編碼decode的做用是將其餘編碼的字符串轉換成unicode編碼,如str1.decode('gb2312'),表示將gb2312編碼的字符串str1轉換成unicode編碼。 encode的做用是將unicode編碼轉換成其餘編碼的字符串,如str2.encode('gb2312'),表示將unicode編碼的字符串str2轉換成gb2312編碼。
所以,轉碼的時候必定要先搞明白,字符串str是什麼編碼,而後decode成unicode,而後再encode成其餘編碼。代碼中字符串的默認編碼與代碼文件自己的編碼一致。
如:s='中文' 若是是在utf8的文件中,該字符串就是utf8編碼,若是是在gb2312的文件中,則其編碼爲gb2312。這 種狀況下,要進行編碼轉換,都須要先用decode方法將其轉換成unicode編碼,再使用encode方法將 其轉換成其餘編碼。一般,在沒有指定特定的編碼方式時,都是使用的系統默認編碼建立的代碼文件
python默認編碼
default encodings in Python are: Python 2.x: ASCII Python 3.x: UTF-8
win7中文環境中對應的系統參數
print('<strong>python系統參數:') print(locale.getdefaultlocale()) #('zh_CN', 'cp936') print(locale.getpreferredencoding()) # cp936 print(sys.getdefaultencoding()) #utf-8 print(sys.getfilesystemencoding())#mbcs print(sys.maxunicode) print(codecs.lookup('utf-8'))#codeinfo class
('zh_CN', 'cp936') cp936 utf-8 mbcs 1114111
utf-8, gbk codecs error
ch_str = '中文' try: codecs_decode(codecs_encode(ch_str,'gbk')) except Exception: print('<strong>utf-8 codec decode error') codecs_decode(codecs_encode('1ère Recuérdame écouteur ça')) codecs_decode(codecs_encode('1ère Recuérdame écouteur ça'),'gbk') try: codecs_decode(codecs_encode('1ère','gbk')) except Exception: print('<strong>utf-8 codec decode error') code_str = '中國' print(code_str.encode().decode()) print(code_str.encode().decode('mbcs','ignore')) try: print(code_str.encode().decode('gbk','strict')) except Exception: print('<strong>gbk codec decode error')
binary寫文件
#write french in file def write_file(filename): with open(filename,'wb') as file: file.write('ry dialect: /a/, /ɑ/, /e/, /ɛ/, /ə/, /i/, /o/, /ɔ/, /'.encode()) def write_file_append(filename,string): line_list = [] with open(filename,'rb') as file: for line in file: line_list.append(line) with open(filename,'wb') as file: for i in range(len(line_list)): file.write(line_list[i]) file.write(string.encode())
python unicode howto:(unicode codepoints): http://docs.python.org/3/howto/unicode.html
python unicode&encoding: http://docs.python.org/3.3/library/codecs.html#encodings-and-unicode
unicode further reading : http://www.diveinto.org/python3/strings.html#py-encoding
new in the python3.0: http://docs.python.org/3.0/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit
codecs test: http://pymotw.com/2/codecs/
py33 file (locale.getpreferredencoding()): http://www.diveinto.org/python3/files.html
py33 io (buffering): http://docs.python.org/3.1/library/io.html#io.TextIOWrapper
py33 shutil(high-level operations on files): http://docs.python.org/3.3/library/shutil.html
codecs源碼:(C:\Python33\Lib\codecs.py)
PEP and ISSUES:
distutils.commands.bdist_wininst.bdist_wininst.get_inidata use mdcs encodinghttp://bugs.python.org/issue10945
bytes.decode('mbcs', 'ignore') does replace undecodable bytes on Windows Vista or laterhttp://bugs.python.org/issue12281
Flexible String Representation http://www.python.org/dev/peps/pep-0393/#discussion
PEP0263: Defining Python Source Code Encodings http://www.python.org/dev/peps/pep-0263/
p.s.
(因爲sublime自身的編碼緣由,因此可能形成在ctrl+b編譯的過程當中,對多語言的編碼出現錯誤)