python unicode 問題 decode encode

這個問題,是很多人的困擾。我們知道所有的文字在電腦中都有編碥。當我們按下鍵盤的 a 這個字母時,電腦作業系統本身並不是收到一個 a 字母,而是一個號碼 97,再從97 查出是a這個字母。這就是編碼。為什麼需要這樣做,因為文字就是一個圖。如果由鍵盤送出的訊號
是以圖為單位來傳送,那傳輸的硬體就要多設計頻寬。鍵盤本身也要存放這些文字的圖。要這樣設計硬體也不是不可以,但這個設計就不是很聰明。

早期電腦的編碼是為了對應鍵盤上的鍵,產生了 ascii 碼。一個由8bit編碼的對應系統。可想而知。8bit也就只能對應256個文字。那全世界其它語言怎麼辨呢?當然就開始出現其它編碼。下面是一些常見的碼

gbk 這個編碼包含了 繁簡中文,日文

windows 中的
cp950 繁中
cp932 日文
cp1250 中歐語言

cjk 中日韓

big5 繁中

Shift_JIS 日文

當一個系統慢慢的出現在各個國家的時候,上面這些編碼就各自出現了。

隨著編碼越來越多,人們就會問,有那麼多編碼,為什麼不建一個完整的,把所有編碼都包進來的統一編碼呢?是的,unicode就是這樣的產物。

進入我們今天的主題。
unicode 國際組織制定的,包括全世界所有語言文字與符號。 針對unicode又產生utf8,utf16,utf32的編碼。這裡很重要。utf8,utf16,utf32是針對unicode,如果拿gbk要改為utf8那是行不通的。必需要gbk先轉成unicode,再由unicode轉為utf8或是utf16,或是utf32。

所以為什麼我們在寫python開頭要加這一行
# -*- coding: utf-8 -*-

就是讓python知道,他接下來要處理的程式中有 unicode 的非英語系文字。編碼要用utf8。
為什麼我們還是常常在python(2.7)遇到中文問題,尤其是換作業系統的時候?

我們先試一下
>>>a="我是人"
>>>len(a)
9
>>>type(a)
<type 'str'>
>>>a=u"我是人"
>>>len(a)
3
>>>type(a)
<type 'unicode'>
>>>b=a.encode('utf8')
>>>type(b)
<type 'str'>
>>>len(b)
9

上面的過程,我們會發現python對字串的處理是用str這個型態。而str這個型態是以byte為單位。所以當我們第一個len(a)時會出現9,因為是 9 個byte。而不是以文字為單位,"我是人"是三個字。

接下來我們用到 u 這個指示字,代表"我是人"是用unicode為編碼,所以len(a)就是3。unicode是以文字為單位。我們再把a用utf8編碼。對python來說,就變為str型態,所以len(b)又變為9 (9個byte)。如果我們要比對字串,只有相同編碼比對才有意義。

這裡我們用到encode這個指令。python中,encode(編碼)是從unicode 編成其它碼。而decode (解碼)是從其它碼"解編碼"為unicode。也就是說所有str型態只能用decode。

我們換平台時為什麼會常常遇到問題,通常是python程式需要讀作業系統的檔案。往往我們在mac上沒問題的比對字串,放到windows系統上就會出問題。因為python讀進來的字串都是str型態。我們必需知道在windows中的文字編碼是什麼,將其decode為unicode。個人最常遇到的就是windows中讀檔名,都是cp950編碼。每個讀進來的名字都要xxxx.decode('cp950').encode('utf8') 。指定錯了編碼是轉不回unicode的。最怕的是文字檔,連編碼都不知道怎麼辨!

目前比較多人用chardet
pip install chardet

用法
>>>import chardet
>>>a = "我是人"
>>>chardet.detect(a)
{'confidence': 0.8765, 'language': '', 'encoding': 'utf-8'}

用這個chartdet查看之後。就可以知道是什麼編碼。









留言

這個網誌中的熱門文章

python 找圖自動點擊

Python pyserial 抓取系統內的 COM PORT

VBA EXCEL 工作表變化 馬上執行 的作法 Worksheet_Change