一、先說說編解碼問題
編碼轉換時,通常需要以unicode作為中間編碼,即先將其他編碼的字符串解碼(decode)成unicode,再從unicode編碼(encode)成另一種編碼。
Eg:
str1.decode('gb2312') #將gb2312編碼的字符串轉換成unicode編碼 str2.encode('gb2312') #將unicode編碼的字符串轉換成gb2312編碼
python2.7 idle GUI界面打印中文會出現亂碼,這是idle本身問題:
cmd界面的python2.7則是正常的:
注意事項:
- s='中文' 如果是在utf8的文件中,該字符串就是utf8編碼,如果是在gb2312的文件中,則其編碼為gb2312。這種情況下,要進行編碼轉換,都需要先用decode方法將其轉換成unicode編碼,再使用encode方法將其轉換成其他編碼。
- 在沒有指定特定的編碼方式時,都是使用的系統默認編碼創建的代碼文件。
- 如果字符串是這樣定義: s=u'中文' 則該字符串的編碼就被指定為unicode了,即python的內部編碼,而與代碼文件本身的編碼無關。只需要直接使用encode方法將其轉換成指定編碼即可
- 如果一個字符串已經是unicode了,再進行解碼則將出錯,因此通常要對其編碼方式是否為unicode進行判斷isinstance(s, unicode) #用來判斷是否為unicode
二、查看文本編碼的方式
1. notepad
對於我們經常使用的記事本,“文件” -> “另存為”,可查看到當前的編碼方式:
2.notepad++
點擊“菜單欄” -> “格式”可以查看到:
還可直接對其進行轉換,轉換完成后保存文件。
3.UltraEdit
不同編碼的文本,是根據文本的前兩個字節來定義其編碼格式的,定義如下:
ANSI: 無格式定義;
Unicode: 前兩個字節為FFFE;
Unicode big endian: 前兩字節為FEFF;
UTF-8: 前兩字節為EFBB;
這樣通過前面兩個字節就可以判定出文件的具體格式了。
三、系統中常見的編碼方式
1.ASCII編碼
上世紀70年代,美國國家標准協會(American National Standard Institute , ANSI )制訂了ASCII碼(American Standard Code for Information Interchange,美國標准信息交換碼)
使用7 位二進制數共128個組合來表示所有的大寫和小寫字母,數字0 到9、標點符號, 以及在美式英語中使用的特殊控制字符。
第0~32號及第127號(共34個)是控制字符或通訊專用字符,如控制符:LF(換行)、CR(回車)、FF(換頁)、DEL(刪除)、BEL(振鈴)等
第33~126號(共94個)是字符,其中第48~57號為0~9十個阿拉伯數字;65~90號為26個大寫英文字母,97~122號為26個小寫英文字母,其余為一些標點符號、運算符號等。
最高位(b7)用作奇偶校驗位,所謂奇偶校驗,是指在代碼傳送過程中用來檢驗是否出現錯誤的一種方法,一般分奇校驗和偶校驗兩種:
- 奇校驗規定:正確的代碼一個字節中1的個數必須是奇數,若非奇數,則在最高位b7添1
- 偶校驗規定:正確的代碼一個字節中1的個數必須是偶數,若非偶數,則在最高位b7添1
2.擴展的ASCII編碼
一個字節中的后7位總共只能表示128個不同的字符,英語用這些字符已經足夠了,可是要表示其他語言卻是不夠。比如,在法語中,字母上方有注音的符號,就無法用ASCII表示。於是,一些國家就利用了字節中閑置的最高位編入新的符號。這樣一來,就可以表示最多256個符號,這就是擴展ASCII 碼,所以現在有7位和8位的兩種ASCII碼,擴展的ASCII 碼允許將每個字符的第8 位用於確定附加的128 個特殊符號字符、外來語字母和圖形符號。但是,不管怎樣,0~127表示的字符是一樣的,不同的只是128~255.
3.ANSI編碼
也是美國國家標准協會(American National Standard Institute , ANSI )制訂的標准。為使計算機支持更多語言,通常使用 0x80~0xFF 范圍的 2 個字節來表示 1 個字符。比如:漢字 '中' 在中文操作系統中,使用 [0xD6,0xD0] 這兩個字節存儲。
不同的國家和地區制定了不同的標准,由此產生了 GB2312, BIG5, JIS 等各自的編碼標准。這些使用 2 個字節來代表一個字符的各種漢字延伸編碼方式,稱為 ANSI 編碼。
- 在簡體中文系統下,ANSI 編碼代表 GB2312 編碼
- 在日文操作系統下,ANSI 編碼代表 JIS 編碼
不同 ANSI 編碼之間互不兼容,當信息在國際間交流時,無法將屬於兩種語言的文字,存儲在同一段 ANSI 編碼的文本中。
ANSI編碼表示英文字符時用一個字節,表示中文用兩個字節,而unicode不管表示英文字符還是中文都是用兩個字節來表示。
4.Unicode編碼
Unicode字符集編碼是Universal Multiple-Octet Coded Character Set 通用多八位編碼字符集的簡稱,是國際組織制定的可以容納世界上所有文字和符號的字符編碼方案。
但即使擴展到256個符號也不夠用,比如漢字據統計有10萬個以上,而且同一個數值在各國的語言中表示的卻不同,比如130在法語里面é,而在希臘語里面則代表Gimel,於是UNICODE應運而生。
Unicode是一種在計算機上使用的字符編碼。它為每種語言中的每個字符設定了統一並且唯一的二進制編碼,以滿足跨語言、跨平台進行文本轉換、處理的要求。Unicode 標准始終使用十六進制數字,而且在書寫時在前面加上前綴“U+”,例如字母“A”的編碼為 004116 和字符“?”的編碼為 20AC16。所以“A”的編碼書寫為“U+0041”。但Unicode只是一個符號集,它只規定了符號的二進制代碼,卻沒有規定這個二進制代碼應該如何存儲。
5.UTF8編碼
事實證明,對可以用ASCII表示的字符使用UNICODE並不高效,因為UNICODE比ASCII占用大一倍的空間,而對ASCII來說高字節的0對 他毫無用處。為了解決這個問題,就出現了一些中間格式的字符集,他們被稱為通用轉換格式,即UTF(Universal Transformation Format)。目前存在的UTF格式有:UTF-7, UTF-7.5, UTF-8, UTF-16, 以及 UTF-32。
UTF-8(8-bit Unicode Transformation Format)是一種針對Unicode的可變長度字符編碼(定長碼),也是一種前綴碼。它可以用來表示Unicode標准中的任何字符,且其編碼中的第 一個字節仍與ASCII兼容,這使得原來處理ASCII字符的軟件無須或只須做少部份修改,即可繼續使用。因此,它逐漸成為電子郵件、網頁及其他存儲或傳 送文字的應用中,優先采用的編碼。
UTF-8用1~4個字節對Unicode進行編碼。從Unicode到UTF-8的編碼方式如下:
000000 - 00007F║0xxxxxxx
000080 - 0007FF║110xxxxx 10xxxxxx
000800 - 00FFFF║1110xxxx 10xxxxxx 10xxxxxx
010000 - 10FFFF║11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
對於0x00-0x7F之間的字符,UTF-8編碼與ASCII編碼完全相同;
帶有附加符號的拉丁文、希臘文、西里爾字母、亞美尼亞語、希伯來文、阿拉伯文、敘利亞文及它拿字母則需要二個字節編碼(Unicode范圍由);
其他基本多文種平面(BMP)中的字符(這包含了大部分常用字)使用三個字節編碼;
其他極少使用的Unicode 輔助平面的字符使用四字節編碼;
UTF-8編碼的最大長度是4個字節。從上表可以看出,4字節模板有21個x,即可以容納21位二進制數字。Unicode的最大碼位0x10FFFF也只有21位。
UTF-8解析算法:
如果字節(Byte)的第一位為0,則B為ASCII碼,並且Byte獨立的表示一個字符;
如果字節(Byte)的第一位為1,第二位為0,則Byte為一個非ASCII字符(該字符由多個字節表示)中的一個字節,並且不為字符的第一個字節編碼;
如果字節(Byte)的前兩位為1,第三位為0,則Byte為一個非ASCII字符(該字符由多個字節表示)中的第一個字節,並且該字符由兩個字節表示;
如果字節(Byte)的前三位為1,第四位為0,則Byte為一個非ASCII字符(該字符由多個字節表示)中的第一個字節,並且該字符由三個字節表示;
如果字節(Byte)的前四位為1,第五位為0,則Byte為一個非ASCII字符(該字符由多個字節表示)中的第一個字節,並且該字符由四個字節表示。
6.ANSI與ASCII編碼區別
- 字面上差異:ANSI指美國國家標准協會,ASCII指美國信息互換標准代碼
- ANSI可以說是ASCII的擴展(為了支持非拉丁語系的語言)一方面,他將ascii碼擴展到8bits,增加了0x80-0xff共128個字符。另一方面,在cjk(chinese japanese korean)系統中,ANSI在不同語言中有不同的具體標准,在簡體中文系統下,ANSI 編碼代表 GB2312 編碼,在日文操作系統下,ANSI 編碼代表 JIS 編碼。
- ansi編碼,就是一種未經國際標准化的編碼(也沒辦法標准化,因為擴展部分的內碼存在交集);而Unicode為國際化的編碼。
7.GB2312
7.1 名稱及制定時間
《信息交換用漢字編碼字符集》是由中國國家標准總局1980年發布,標准號是GB 2312—1980,所以簡稱為GB2312。
7.2 編碼格式
在使用GB2312的程序中,通常采用EUC儲存方法,以便兼容於ASCII。瀏覽器編碼表上的“GB2312”,通常都是指“EUC-CN”表示法。
每個漢字及符號以兩個字節來表示。第一個字節稱為“高位字節”(也稱“區字節)”,第二個字節稱為“低位字節”(也稱“位字節”)。
“高位字節”使用了0xA1-0xF7(把01-87區的區號加上0xA0),“低位字節”使用了0xA1-0xFE(把01-94加上 0xA0)。 由於一級漢字從16區起始,漢字區的“高位字節”的范圍是0xB0-0xF7,“低位字節”的范圍是0xA1-0xFE,占用的碼位是 72*94=6768。其中有5個空位是D7FA-D7FE。
例如“啊”字在大多數程序中,會以兩個字節,0xB0(第一個字節) 0xA1(第二個字節)儲存。區位碼=區字節+位字節(與區位碼對比:0xB0=0xA0+16,0xA1=0xA0+1)。
GB 2312標准共收錄6763個漢字,其中一級漢字3755個,二級漢字3008個;同時,GB 2312收錄了包括拉丁字母、希臘字母、日文平假名及片假名字母、俄語西里爾字母在內的682個全角字符。
7.3 特點
GB 2312的出現,基本滿足了漢字的計算機處理需要,它所收錄的漢字已經覆蓋中國大陸99.75%的使用頻率。
對於人名、古漢語等方面出現的罕用字,GB 2312不能處理,這導致了后來GBK及GB 18030漢字字符集的出現。
8.GBK
8.1 名稱及制定時間
GBK全稱《漢字內碼擴展規范》,全國信息技術標准化技術委員會1995年12月1日制訂。
8.2 編碼格式
GBK編碼,是在GB2312-80標准基礎上的內碼擴展規范,使用了雙字節編碼方案,其編碼范圍從8140至FEFE(剔除xx7F),共23940個碼位,共收錄了21003個漢字,完全兼容GB2312-80標准,支持國際標准ISO/IEC10646-1和國家標准GB13000-1中的全部中日韓漢字,並包含了BIG5編碼中的所有漢字。GBK編碼方案於1995年10月制定, 1995年12月正式發布,目前中文版的WIN95、WIN98、WINDOWS NT以及WINDOWS 2000、WINDOWS XP、WIN 7等都支持GBK編碼方案。
GBK 是 GB2312的擴展 ,除了兼容GB2312外,它還能顯示繁體中文,還有日文的假名。
8.3 說明
GB2312是中國規定的漢字編碼,也可以說是簡體中文的字符集編碼;GBK 是 GB2312的擴展 ,除了兼容GB2312外,它還能顯示繁體中文,還有日文的假名。
9.Python idle默認編碼方式
如下操作均在Python2.7 idle中實驗
說明:1.'a'的編碼仍然是'a',‘中'編碼為0xd6和0xd0兩個字節( 而且是0x80~0xFF 范圍內),說明編碼方式為擴展的ASCII(ANSI)
參考http://www.cnblogs.com/TsengYuen/archive/2012/05/22/2513290.html
http://wenku.baidu.com/link?url=DW_eaIYsVuh31R7FHY8nQa3jiyrtnH6rIc5zoseS8apT0vN9exCFteyfcAm30USuphTdKqsOSAwaU7QeqdpK7u4-Gpr2WULF8PLwlY3bafq
后續繼續更新
四、Python模塊之codecs
python對多國語言的處理是支持的很好的,它可以處理現在任意編碼的字符,這里深入的研究一下python對多種不同語言的處理。
有一點需要清楚的是,當python要做編碼轉換的時候,會借助於內部的編碼,轉換過程請參考上文第一張圖片。
Unicode編碼有兩種,一種是UCS-2,用兩個字節編碼,共65536個碼位;另一種是UCS-4,用4個字節編碼,共2147483648個碼位。
python都是支持的,這個是在編譯時通過--enable- unicode=ucs2或--enable-unicode=ucs4來指定的。那么我們自己默認安裝的python有的什么編碼怎么來確定呢?有一個 辦法,就是通過sys.maxunicode的值來判斷:
import sys print sys.maxunicode
如果輸出的值為65535,那么就是UCS-2,如果輸出是1114111就是UCS-4編碼。
我們要認識到一點:當一個字符串轉換為內部編碼后,它就不是str類型了!它是unicode類型
a = " 風卷殘雲 " print type(a) b = unicode(a,‘gb2312') print type(b)
運行結果:
<type 'str'> <type 'unicode'>
這個時候b可以方便的任意轉換為其他編碼,比如轉換為utf-8
c = b.encode(’utf8') print c
好了,該說說codecs模塊了,它和我上面說的概念是密切相關的。codecs專門用作編碼轉換,當然,其實通過它的接口是可以擴展到其他關於代碼方面的轉換的,這個東西這里不涉及。
參考文檔:
http://xanderzhang.iteye.com/blog/465992
http://jingyan.baidu.com/article/48b558e367b1fe7f38c09a87.html
http://blog.163.com/yang_jianli/blog/static/161990006201371451851274
http://san-yun.iteye.com/blog/1544123