python編碼的那些事

任平生78發表於2017-11-08

字串編碼在python裡是經常會遇到的問題,特別是寫檔案或是網路傳輸呼叫某些函式的時候.

現在來看看python中的unicode編碼和utf-8編碼

字串編碼的歷史

  1. 計算機只能處理數字,文字轉換為數字才能處理. 計算機中8個bit作為一個位元組,所以一個位元組能表示最大的數字為255

  2. 計算機是美國人發明的,一個位元組就可以表示所有的英文字元了,所以ACSII(一個位元組)編碼就成為美國人的標準編碼

  3. 但是中文裡遠遠不止255個漢字,這時用ASCII來處理中文是明顯不夠用的,所以我國制定了GB2312編碼,用兩個位元組表示一個漢字.

GB2312還把ASCII包含進去.同理,別的國家為了解決自己國家的編碼問題也都發展了一套位元組的編碼,這樣標準就越來越多.

如果一篇文章出現多種語言混合顯示就一定會出現亂碼.

  1. 這裡unicode出現了,unicode把所有的語言統一到一套編碼裡.

  2. 看一下ASCII編碼和unicode編碼:
    字母A用ASCII編碼十進位制是65,二進位制是0100 00001
    漢字”中”已經超出了ASCII編碼的範圍,用unicode編碼是20013,二進位制是0100 1110 0010 1101
    A用unicode編碼只需要前面補0,二進位制是00000000 0100 0001

  3. 亂碼問題解決了,但是如果一段內容全是英文,unicode編碼比ASCII需要多一倍的儲存空間,浪費很多硬碟容量.同時傳輸時也需要多浪費很多頻寬.

  4. “utf-8″會把英文變成一個位元組,漢字3個位元組.特別生僻的變成4到6個位元組.如果傳輸的英文,就把英文輪換成unicode編碼格式.

python儲存檔案和讀取檔案時編碼的關係

儲存檔案時,把unicode編碼轉換成utf-8編碼格式
讀取檔案時,把utf-8編碼轉換成unicode編碼格式

分別在windows系統和linux系統中測試python2和python3的編碼區別

windows系統的python2版本

    Python 2.7.13 (v2.7.13:a06454b1afa1, Dec 17 2016, 20:53:40) [MSC v.1500 64 bit (AMD64)] on win32
    >>> str1="hello"                # 因為str1和str2都是英文,所以atr1和str2不管是unicode編碼還是ASCII格式
    >>> str2=u"hello"               # encode成utf-8編碼時都不會出現錯誤
    >>> str1.encode("utf-8")
    `hello`
    >>> str2.encode("utf-8")
    `hello`
    
    >>> type(str1)
    <type `str`>
    >>> type(str2)
    <type `unicode`>
    
    >>> str3="我用python"             # python中的字串在記憶體中是用unicode來編碼的
    >>> str4=u"我用python"            # str3在windows系統中儲存成GBK編碼
    >>> str3.encode("utf-8")            # str3在呼叫encode方法之前必須轉換為unicode編碼
    Traceback (most recent call last):      # 此時str3應該先decode成為unicode編碼,然後再encode成utf-8編碼
      File "<input>", line 1, in <module>
    UnicodeDecodeError: `ascii` codec can`t decode byte 0xe6 in position 0: ordinal not in range(128)
    
    >>> str3.decode("utf-8")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "D:Python27libencodingsutf_8.py", line 16, in decode
        return codecs.utf_8_decode(input, errors, True)
    UnicodeDecodeError: `utf8` codec can`t decode byte 0xce in position 0: invalid c
    ontinuation byte
    
    >>> str3.decode(`gbk`)
    u`u6211u7528python`   
    
    >>> str3.decode("utf-8").encode("utf-8")
    `xe6x88x91xe7x94xa8python`
    
    >>> str4.encode("utf-8")
    `xe6x88x91xe7x94xa8python`
    
    >>> type(str3)
    <type `str`>
    >>> type(str4)
    <type `unicode`>
    
    >>> import sys
    >>> sys.getdefaultencoding()
    `ascii`

windows系統的python3版本

    Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> str1="hello"                        # python3中所有的字串都是unicode編碼
    >>> str2=u"hello"
    >>> str1.encode("utf-8")
    b`hello`
    >>> str2.encode("utf-8")
    b`hello`
    >>> str3="我用python"
    >>> str3.encode("utf-8")
    b`xe6x88x91xe7x94xa8python`
    >>> str4=u"我用python"
    >>> str4.encode("utf-8")
    b`xe6x88x91xe7x94xa8python`
    
    >>> import sys
    >>> sys.getdefaultencoding()  
    `utf-8`

linux系統的python2版本

    Python 2.7.5 (default, Nov  6 2016, 00:28:07) 
    [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> str1="我用python"             
    >>> str1.encode("utf-8")            
    Traceback (most recent call last):      
      File "<stdin>", line 1, in <module>
    UnicodeDecodeError: `ascii` codec can`t decode byte 0xe6 in position 0: ordinal not in range(128)
    
    >>> str1.decode("gbk")                          
    u`u93b4u6220u6564python`                     
    >>> str1.decode(`utf-8`)                        # linux系統中python2會把字串儲存成utf-8編碼,那為什麼不能直接encode呢?
    u`u6211u7528python`                           # 字串在encode之前應該保證是一個unicode編碼格式,字串在encode之前
                                                    # 會呼叫decode方法把字串轉換成unicode編碼,然後才能encode
    >>> str1.decode("utf-8").encode("utf-8")        # str1字串中含有中文,直接encode成utf-8編碼會出現錯誤
    `xe6x88x91xe7x94xa8python`
    
    >>> str1.decode("gbk").encode("utf-8")
    `xe9x8exb4xe6x88xa0xe6x95xa4python`
    
    >>> str2=u"我用python"
    >>> str2.encode("utf-8")
    `xe6x88x91xe7x94xa8python`
    
    >>> type(str1)
    <type `str`>
    >>> type(str2)
    <type `unicode`>
    
    >>> import sys
    >>> sys.getdefaultencoding()
    `ascii`

linux系統的python3版本

    Python 3.6.3 (default, Nov  7 2017, 20:33:25) 
    [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> str1="我用python"                     # python3中所有的字串都是unicode編碼
    >>> str2=u"我用python"
    >>> str1.encode("utf-8")
    b`xe6x88x91xe7x94xa8python`
    >>> str2.encode("utf-8")
    b`xe6x88x91xe7x94xa8python`
    
    >>> import sys
    >>> sys.getdefaultencoding()  
    `utf-8`

不管是windows系統還是linux系統,python2版本中預設使用ASCII編碼,python3版本預設使用utf-8編碼


相關文章