天天看點

python編碼的那些事

字元串編碼在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:\Python27\lib\encodings\utf_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'\u6211\u7528python'   
    
    >>> str3.decode("utf-8").encode("utf-8")
    '\xe6\x88\x91\xe7\x94\xa8python'
    
    >>> str4.encode("utf-8")
    '\xe6\x88\x91\xe7\x94\xa8python'
    
    >>> 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'\xe6\x88\x91\xe7\x94\xa8python'
    >>> str4=u"我用python"
    >>> str4.encode("utf-8")
    b'\xe6\x88\x91\xe7\x94\xa8python'
    
    >>> 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'\u93b4\u6220\u6564python'                     
    >>> str1.decode('utf-8')                        # linux系統中python2會把字元串儲存成utf-8編碼,那為什麼不能直接encode呢?
    u'\u6211\u7528python'                           # 字元串在encode之前應該保證是一個unicode編碼格式,字元串在encode之前
                                                    # 會調用decode方法把字元串轉換成unicode編碼,然後才能encode
    >>> str1.decode("utf-8").encode("utf-8")        # str1字元串中含有中文,直接encode成utf-8編碼會出現錯誤
    '\xe6\x88\x91\xe7\x94\xa8python'
    
    >>> str1.decode("gbk").encode("utf-8")
    '\xe9\x8e\xb4\xe6\x88\xa0\xe6\x95\xa4python'
    
    >>> str2=u"我用python"
    >>> str2.encode("utf-8")
    '\xe6\x88\x91\xe7\x94\xa8python'
    
    >>> 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'\xe6\x88\x91\xe7\x94\xa8python'
    >>> str2.encode("utf-8")
    b'\xe6\x88\x91\xe7\x94\xa8python'
    
    >>> import sys
    >>> sys.getdefaultencoding()  
    'utf-8'           

不管是windows系統還是linux系統,

python2版本中預設使用ASCII編碼

,

python3版本預設使用utf-8編碼