python3.3 unicode(encode&decode)

最近在用python寫多語言的一個插件時,涉及到python3.x中的unicode和編碼操做,本文就是針對編碼問題研究的彙總,目前已開源至github。如下內容來自項目中的README。html

1 ASCII、UNICODE、GBK、CP93六、MSCS

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。

2 open函數

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().

3 encode和decode方法

字符串在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方法將 其轉換成其餘編碼。一般,在沒有指定特定的編碼方式時,都是使用的系統默認編碼建立的代碼文件

4 相關代碼

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())

5 參考資料

PEP and ISSUES:


  • 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

  • PEP393:

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.


  • sublime3/2的錯誤編碼

(因爲sublime自身的編碼緣由,因此可能形成在ctrl+b編譯的過程當中,對多語言的編碼出現錯誤)

相關文章
相關標籤/搜索