1. 程式人生 > >python - 字符編碼篇

python - 字符編碼篇

占用 logs utf blank big5 tro 自然 成了 數據庫

本章內容

  1. 什麽是字符編碼?
  2. python默認編碼
  3. decode(解碼)和encode(編碼)

前言

  對於字符編碼的問題,在學習python的過程中,很多新手都為之瘋狂,本人也是其中之一,所以就來懟這個問題了。

一、什麽是字符編碼

  首先我們得知道,計算機中的所有數據,不管是文字、圖片、視頻、還是音頻文件,本質上最終都是按照二進制存儲的(就是一堆只有0、1的數字),並且計算機是只認識數字的,它並不認識你是 "A" 它是 "B" 。到這裏需要先說一下,計算機的母語就是英語嘛,所以剛開始也就只是用的英語啦。我們還知道1 bytes = 8 bit ,也就是說一個字節等於8位,8位可以表達多少種不同的情況?每一位可以為0或1,那麽8位則是2**8(2的8次方啊),也就是256種情況。然後呢計算機初期也只在美國使用,他們把數字、字母(包括大小寫)、標點符號、空格這些基本要用的都加起來也只有127個,所以256完完全全夠他們用了。於是他們用一個字節、用多種組合來存儲英語的文字了。這樣計算機認識這個數字的情況就相當於認識了這些字符,於是計算機就支持了英語這一門語言了。接下來進入正題:

  字符編碼:(英語:Character encoding)也稱字集碼,是把字符集中的字符編碼為指定集合中某一對象(例如:比特模式、自然數序列、8位組或者電脈沖),以便文本在計算機中存儲和通過通信網絡的傳遞。目的就是為了讓計算機能 "認識" 字符。

  ASCII:上個世紀60年代,美國制定了一套字符編碼,對英語字符與二進制位之間的關系,做了統一規定。這被稱為ASCII碼,一直沿用至今。其實就是開頭講的東西,應該不難理解。ASCII碼使用7位2進制數表示一個字符,7位2進制數可以表示出2的7次方個字符,共128個字符。

  隨著計算機的大量使用,僅僅是英文字符已經不能滿足各個國家的需求了,於是各國紛紛開始對ASCII碼後面的編碼進行搶占啊,哈哈。然後呢就出現了各種各樣的編碼。詳細的編碼發展歷史見本節尾部。

  ANSI:一種字符代碼,為使計算機支持更多語言,通常使用 0x00~0x7f 範圍的1 個字節來表示 1 個英文字符,即ASCII編碼(只用了7位)。超出此範圍的使用0x80~0xFFFF來編碼,即擴展的ASCII編碼(用了8位)。在 ASCII 範圍內它們應該是和 ASCII 一致的。Windows裏的 ANSI 其實是Windows code pages,簡體中文編碼GBK,實際上它是 ANSI 的一個代碼頁 936 。

  註:128位到255的字符集對應拉丁文。一個字節就滿了。

  GB2312:從上面我們知道了,計算機已經可以 "認識" 英文,但是不認識中文啊,而且一個字節也用完了,那怎麽辦?於是牛逼的中國人,重新寫了一張表,把第8位對應的拉丁文全給刪了,哈哈,然後規定一個小於127的字符的意義與原來相同,但兩個大於127的字符連在一起時就表示一個漢字,於是6000多個漢字就硬生生給造出來了。前面的一個字節(高字節),從0xA1 用高 0xF7,後面一個字節(低字節),從0xA1到0xFE。GB2312其實就是對ASCII 的中文擴展。當然6000多個漢字是肯定不能滿足中文需求的,所有後續又有GB18030和GBK,這個就自己去了解吧。

  UNICODE:由於各個國家都搞出了自己的編碼標準,並且互相又不支持,所以這就造成了很多問題。於是國際標準化組織就搞出了個萬國碼--UNICODE。UNICODE規定用兩個字節來表示一個字符,總共可以組合出65535種不同的字符,這已經足以解決我們編碼與編碼之間的支持問題了。

  UTF-8:UNICODE是支持UTF-8的,為什麽要重新搞個UTF-8?因為UNICODE所有字符都是占2個字節,這樣就使本來1個字節就能搞定的東西,非得用2個存儲,這不是浪費內存嗎?並且我們的程序中英文會遠多余中文,所以位了節省內存,就搞出了UTF-8。UTF-8規定,英文只用一個字節,中文用3個字節。

  UTF-8版本雖然具有良好的國際兼容性,但中文需要比GBK/BIG5版本多占用50%的數據庫存儲空間,因此並非推薦使用,僅供對國際兼容性有特殊要求的用戶使用。簡單地說:對於中文較多的網站,適宜用GBK編碼節省數據庫空間。對於英文較多的網站,適宜用UTF-8節省數據庫空間。

  以上就是基本的介紹了,詳細發展歷史--->>字符編碼發展歷史

二、Python默認的編碼

  首先我們對操作系統的默認編碼做下基本的了解。windows中文環境下cmd的默認編碼是 GBK ,我們可以在cmd下輸入chcp命令(如下圖),返回結果:活動代碼頁:936(936代表的便是GBK);Linux下的terminal默認編碼為 UTF-8

  在Python中,當源代碼讀取進行語法校驗時,會將源代碼中的字符串從聲明的編碼轉換成 Unicode 類型,等到語法校驗通過後,再將這些字符換回初始的編碼。

技術分享

  • 在python 2.x 環境下

  python2.x 默認編碼為ASCII ,可以通過以下方式可以檢測:

1 import sys
2 sys.getdefaultencoding()

  不過你不要天真的以為你指定編碼為UTF-8就一定能輸出中文了,在Windows下cmd窗口的字符編碼是GBK,規定輸出的字符集必須是GBK的,所以你傳進去UTF-8的中文自然GBK是不兼容的,所以還是亂碼。

  解決方法:

  1.

 1 # _*_ coding:utf-8 _*_
 2 
 3 # 定義一個變量內容為中文,字符集為UTF-8
 4 temp = "中文"
 5 
 6 # 解碼,需要指定原來是什麽編碼
 7 temp_unicode = temp.decode("utf-8")
 8 
 9 # 編碼,需要指定要轉換成什麽編碼
10 temp_gbk = temp_unicode.encode("gbk")
11 
12 # 輸出轉換成的gbk編碼
13 print(temp_gbk)

  2.

 1 # _*_ coding:utf-8 _*_
 2 
 3 # 定義一個變量內容為中文,字符集為UTF-8
 4 temp = "中文"
 5 
 6 # 解碼,需要指定原來是什麽編碼
 7 temp_unicode = temp.decode("utf-8")
 8 
 9 # 輸出轉換成的gbk編碼
10 print(temp_unicode)
11 # Windows終端需要GBK,DOS自動轉換成GBK
12 
13 註:decode() 和 encode() 將在下一小節進行整理
  • 在python 3.x 環境下

  通過以上方法可以知道python3.x 默認編碼為 UTF-8 。python 2.x 到 3.x 編碼的問題有了很大的改進。2.x中編碼的問題絕對會讓你頭疼,而3.x則輕松得多。雖然在 2.x 和 3.x 中都引入了Unicode,但是在 2.x 中的字符串有兩種類型(unicode和str),默認是str類型,也就是說如果你要改變一個字符串的編碼,你得先解碼(decode)成unicode,然後再編碼(encode)成你所要轉的編碼;而在 3.x 中默認就是unicode類型,例:字符串不再區分"abc"和u"abc", 字符串"abc"默認就是unicode。

  盜alex老師的一個圖,下圖只適用於python 2.x:

技術分享

  • 再說一下Unicode

  python之所以這麽受歡迎,跟它引入了Unicode有莫大的關系,因為對不同國家和地區所用的字符的友好支持。

  現在我們來考慮一下,我們上面已經說了在python2.x 環境下,默認是ASCII,那麽我們寫代碼時出現了ASCII不支持的字符,那怎麽辦?我們先看一個圖:

技術分享

    (圖片來源:http://nltk.googlecode.com/svn/trunk/doc/book/ch03.html)

  這個圖我們可以看出來,所有超出ASCII範圍的字符處理工作,無論是在輸入之前,或者輸出之後是什麽編碼格式,它們在python的執行內存中,都統一被解碼(decode)成了Unicode格式。所以Unicode啊,這個萬國碼可不是鬧著玩的,完全就是一個中轉站,什麽編碼都能處理。

  註:在python2.x中可以看見 u‘abc‘ 這種前面加 u 的字符串,其實就是說它著是一個unicode類型的字符串,不過在 3 中這個方法被廢棄了,因為不需要了。

三、decode() 和 encode()

  從上述兩點中應該已經能知道這個東西了。

  decode(解碼):清除原有編碼格式,並解碼成unicode。decode是將bytes類型變成str類型。所以,str類型是沒有decode方法的。

  encode(編碼):將unicode轉成其他編碼。encode是將str類型變成bytes類型。bytes類型也沒有encode方法。

  在用這兩個方法的時候經常會犯錯,就是因為不清楚各個字符編碼之間的兼容關系,以及運用對象。所以我們需要弄清楚兼容的問題,比如:UTF-8 和 GBK 都支持中文,但是就是不兼容,一個是從Unicode中提取出的擴展集,另一個則是在ASCII基礎上進行重新修改的字符集。

  還有不清楚的看看以下兩個例子:

技術分享
 1 #-*-coding:utf-8-*-
 2 #指定編碼格式
 3 
 4 import sys
 5 #導入模塊
 6 
 7 print(sys.getdefaultencoding())
 8 #打印默認編碼
 9 
10 name = "裏昂"
11 name_gb2312 = name.decode("utf-8").encode("gb2312")
12 #先解碼成unicode(需指定原編碼格式),再編碼成gb2312
13 
14 gb2312_to_gbk = name_gb2312.decode("gbk").encode("gbk")
15 #先解碼成unicode,同上,再編碼成gbk
16 
17 print(name)
18 #打印名字
19 
20 print(name_gb2312)
21 #打印gb2312編碼下的名字
22 
23 print(gb2312_to_gbk)
24 #打印gbk編碼下的名字
在python 2.x 中 技術分享
 1 import sys
 2 #導入模塊
 3 
 4 print(sys.getdefaultencoding())
 5 #打印默認編碼
 6 
 7 name = "裏昂"
 8 #name_gb2312 = name.decode("utf-8").encode("gb2312")   py2
 9 name_gb2312 = name.encode("gb2312")
10  #py3 默認就是unicode,不用再decode
11 
12 gb2312_to_unicode = name_gb2312.decode("gb2312")
13 #decode成unicode
14 
15 gb2312_to_utf8 = name_gb2312.decode("gb2312").encode("utf-8")
16 #轉成utf-8
17 
18 print(name)
19 #打印名字
20 
21 print(name_gb2312)
22 #打印gb2312編碼下的名字
23 
24 print(gb2312_to_unicode)
25 #打印unicode編碼下的名字
26 
27 print(gb2312_to_utf8)
28 #打印utf-8編碼下的名字
在python 3.x 中

  終於把這玩意搞完了,希望看到的朋友可以幫忙指出不足與錯誤的地方。感謝!

python - 字符編碼篇