[python] python 編碼ASCII、Unicode、utf-8

python 編碼ASCII、Unicode、utf-8

1. python2中我們看到的字符串

#當前系統的默認編碼爲utf-8
In [39]: locale.getdefaultlocale()
Out[39]: ('en_US', 'UTF-8')
    
In [25]: teststr = '聯通'

#在內存中是以utf-8編碼存在的
In [26]: teststr
Out[26]: '\xe8\x81\x94\xe9\x80\x9a'

#可以看到字符串爲指定編碼時,使用的默認編碼utf-8
In [27]: chardet.detect(teststr)
Out[27]: {'confidence': 0.7525, 'encoding': 'utf-8', 'language': ''}

In [28]: teststr.encode('utf-8')
Out[28]: '\xe8\x81\x94\xe9\x80\x9a'

#指定爲Unicode編碼之後,在內存中是以Unicode編碼存在的
In [29]: teststr = u'聯通'
In [31]: teststr
Out[31]: u'\u8054\u901a'
    
In [41]: print(teststr)
聯通

In [32]: teststr.encode('utf-8')
Out[32]: '\xe8\x81\x94\xe9\x80\x9a'

綜上,平時python代碼裏面的字符串,在內存中都是以指定的編碼存儲的; 不指定時,以當前環境的默認編碼存儲的。

2. Unicode編碼

起初由於計算機在美國發明,自然大家考慮的是英語如何表示,英語字母總共26個,加上特殊字符,128個字符,7位既一個byte即可表示出來。這個就是大家所熟知的ascill編碼。對應關係很簡單,一個字符對應一一個byte。

但很快發現,其他非英語國家的文字遠遠超過ascill碼,這時候大家當然想統一字符編碼,不同國家出了自己不同的編碼方式,中國的gb2312就是自 己做出來的編碼方式,這樣下去每個國家都有自己的編碼方式,來回轉換太麻煩了。這時候出現了新的編碼方式,unicode編碼方式,想將編碼統一,所以規 定了每個字符對應的unicode碼。

Unicode(統一碼,萬國碼)是基於通用字符集(Universal Character Set)的標準發展。它爲每種語言中的每個字符設定了統一併且唯一的二進制編碼,以滿足語言、跨平臺進行文本轉換、處理的要求。

​ Unicode用數字0到0X10FFFF來映射這些數字,最多容納1114112個字符。1114112是怎麼計算出來的?將0X10FFFF分成0X10和0XFFFF兩部分。我們知道0XFFFF是65535,那麼 [0,65535] 左右閉區間,總共是65536個。同理,0X10用10進製表示爲16,那麼 [ 0,16 ] 左右閉區間,總共是17個。所以17乘以65536=1114112.

Unicode編碼是一個統一的編碼,其他編碼類型之間相互轉換,都需要先轉成Unicode

如UTF8——>Unicode ——>GBK、GB2312

3. Unicode 的問題

需要注意的是,Unicode 只是一個符號集,它只規定了符號的二進制代碼,卻沒有規定這個二進制代碼應該如何存儲。

比如,漢字的 Unicode 是十六進制數4E25,轉換成二進制數足足有15位(100111000100101),也就是說,這個符號的表示至少需要2個字節。表示其他更大的符號,可能需要3個字節或者4個字節,甚至更多。

這裏就有兩個嚴重的問題,第一個問題是,如何才能區別 Unicode 和 ASCII ?**計算機怎麼知道三個字節表示一個符號,而不是分別表示三個符號呢?**第二個問題是,我們已經知道,英文字母只用一個字節表示就夠了,如果 Unicode 統一規定,每個符號用三個或四個字節表示,那麼每個英文字母前都必然有二到三個字節是0,這對於存儲來說是極大的浪費,文本文件的大小會因此大出二三倍,這是無法接受的。

它們造成的結果是:1)出現了 Unicode 的多種存儲方式,也就是說有許多種不同的二進制格式,可以用來表示 Unicode。2)Unicode 在很長一段時間內無法推廣,直到互聯網的出現。

所以出現了utf-8、gbk 等編碼方式。

如將Unicode以編碼方式utf8編碼之後存儲;在讀取的時候,用utf8解碼爲Unicode顯示;

4. 文件的讀寫

在計算機內存中,統一使用Unicode編碼,當需要保存到硬盤或者需要傳輸的時候,就轉換爲UTF-8編碼。

用記事本編輯的時候,從文件讀取的UTF-8字符被轉換爲Unicode字符到內存裏,編輯完成後,保存的時候再把Unicode轉換爲UTF-8保存到文件:

在這裏插入圖片描述

5. 爲什麼會亂碼

  • 解碼方式跟編碼方式不一致就會導致亂碼, 不涉及到編碼、解碼就不會報錯
    • 寫數據庫時,如果寫如的數據編碼跟數據庫編碼不一樣就會報錯
    • python的print 在打印字符時,以當前環境默認編碼解碼
    • 比如從數據庫獲取的數據是gbk編碼,但是代碼的默認編碼爲utf-8,print時會亂碼; 最好的辦法是入程序時統一轉成Unicode
  • 平時寫程序的時候,好像沒有特別注意編碼,但是出現亂碼很少;
    • 處理邏輯時,如果不decode\encode就不會報錯;當前程序很少decode\encode, 都是讀取數據格式化就數據返回了; 讀取mongo返回的數據是Unicode

6. python2 中的亂碼

  • python2 中默認的編碼是ASCII,需要在首行指定編碼方式,未指定的話,很容易出現亂碼

7. python3 中默認爲utf-8

  • 確保讀入的數據都是utf8編碼的即可正確解碼

8. 數據庫的讀寫

  • MySQL

    • charset : utf-8
    • 寫數據的時候,數據應用被encode(‘utf-8’)
    • 讀取出來的數據,任然是utf-8編碼的,要正常顯示,需要將終端的編碼設置爲utf-8
    • 程序處理時,讀的數據也是utf-8編碼的
  • mongodb pymongo

    MongoDB stores data in BSON format. BSON strings are UTF-8 encoded so PyMongo must ensure that any strings it stores contain only valid UTF-8 data. Regular strings (<type ‘str’>) are validated and stored unaltered. Unicode strings (<type ‘unicode’>) are encoded UTF-8 first. The reason our example string is represented in the Python shell as u’Mike’ instead of ‘Mike’ is that PyMongo decodes each BSON string to a Python unicode string, not a regular str.
    
    • mongo 以utf8格式存儲數據

    • 寫數據時,字符串將被直接寫入; Unicode編碼的,將被首先轉換爲utf8

    • 讀數據時,pymongo將數據轉爲Unicode編碼; 程序內部取數據時候並沒有轉碼,給請求返回的是Unicode的編碼

      In [58]: data = db.wallpaper_category.find_one({'_id': 17})
      
      In [59]: type(data)
      Out[59]: dict
      
      In [60]: data.keys()
      Out[60]: [u'name', u'tag', u'_id', u'w_type', u'order', u'desc']
      
      In [61]: data.items()
      Out[61]: 
      [(u'name', u'keyboard \u5206\u7c7b1'),
       (u'tag', u'keyboard \u5206\u7c7b1'),
       (u'_id', 17),
       (u'w_type', u'keyboard'),
       (u'order', 1),
       (u'desc', u'keyboard \u5206\u7c7b1')]
      
發佈了27 篇原創文章 · 獲贊 3 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章