從Python編碼說開去

2021-08-27 23:52:07 字數 3169 閱讀 5600

python指令碼也就是.py檔案使用unicode編碼作為指令碼編碼,編碼格式是utf8。

unicode編碼: 為世界上所有的文字或字元乙個編碼。這個編碼在unicode中叫做**點(code point)。乙個**點通常表示為「u+ffff」的形式。 所有**點的集合,即unicode字符集叫做ucs(universal character set)。ucs-2 是ucs code in 2 octets,即用兩個位元組表示的ucs,其表示範圍為:u+0000 ~ u+ffff。為了表示更多字元還有ucs-4,即用4個位元組表示的ucs,其表示範圍為:u+00000000 ~ u+7fffffff。ucs-4中u+00000000 ~ u+0000ffff與ucs-2是重疊的,ucs-2是ucs-4的乙個子集。

**點是unicode字元的內碼,但如何儲存這個**點或者說如何儲存這個內碼呢?是直接儲存這個**點(內碼)的值嗎?目前有多種格式。

首先解釋一下大端(big endian)和小端(little endian)。 這個概念是源於**處理器cpu對多位元組資料(如,int 4位元組,char 2位元組等)的處理方式(儲存和傳輸)。一種是多位元組資料的低位位元組可以儲存於記憶體的低位位址,高位位元組依序儲存於高位記憶體位址 - little endian(高位位元組儲存於高位位址);另一種則相反 -  big endian(高位位元組儲存與低位位址)。如xe8af這個字元,高位位元組是e8(11101000) 地位位元組是af(10111111),儲存於記憶體位址為0x00efc77a和0x00efc77b兩個位元組,如下所示:

big endian

0x00efc77a     0x00efc77b

11101000              10111111

little endian

0x00efc77a     0x00efc77b

10111111              11101000

多位元組編碼的字元在記憶體/檔案中儲存時存在大小端的問題。

unicode編碼的儲存方式有:utf16/utf32/utf8 三種格式

utf16:

utf16直接儲存ucs-2內碼值和ucs-2是完全對應的,是一種多位元組(2位元組)編碼。由於位元組序的緣故,utf-16包括三種:utf-16,utf-16be(big endian),utf-16le(little endian)。

utf-16be和utf-16le不難理解,而utf-16就需要通過在檔案開頭以名為bom(byte order mark)的字元來表明檔案是big endian還是little endian。bom為u+feff這個字元。其實bom是個小聰明的想法。由於ucs-2沒有定義u+fffe,因此只要出現 ff fe 或者 fe ff 這樣的位元組序列,就可以認為它是u+feff,並且可以判斷出是big endian還是little endian。

utf32:

類似於ucs-2 和utf16的情況,只是字元用4個位元組表示 和ucs-4完全對應,也存在big endian和little endian的問題。

utf-8:

utf-16和utf-32的乙個缺點就是它們固定使用兩個或四個位元組,很多字元編碼中會有多餘的00,導致傳輸效率降低。而rfc3629定義的utf-8則解決了這個問題。utf-8用1~4個位元組來表示**點,並且定義了每個位元組的格式特徵,因此是一種單位元組編碼方式,不存在big endian和little endian的問題。儲存乙個utf-8字元時,需要將這個字元的unicode內碼,編碼成位元組陣列,然後需要按照陣列的順序,乙個乙個位元組寫入,不用考慮位元組序問題。其實本質是big endian。

表示方式如下:

ucs-2 (ucs-4)

位序列第一位元組

第二位元組

第三位元組

第四位元組

u+0000 .. u+007f

00000000-0******x

0******x

u+0080 .. u+07ff

00000***-xxyyyyyy

110***xx

10yyyyyy

u+0800 .. u+ffff

***xyyyy-yyzzzzzz

1110***x

10yyyyyy

10zzzzzz

u+10000..u+1fffff

00000000-000wwwxx-

***xyyyy-yyzzzzzzz

11110www

10******

10yyyyyy

10zzzzzz

按照utf-8標準: 

(1)所有以0開始的位元組,都與原來的ascii碼相容,也就是說,0******x不需要額外轉換,就是我們平時用的ascii碼。 

(2)所有以10開始的位元組,都不是每個unicode的第乙個位元組,都是緊跟著前一位。例如:10110101,這個位元組不可以單獨解析,必須通過前乙個位元組來解析,如果前乙個也是10開頭,就繼續前嗍。 

(3)所有以11開始的位元組,都表示是unicode的第乙個位元組,而且後面緊跟著若干個以10開頭的位元組。如果是110***xx(就是最左邊的0的左邊有2個1),代表後面還有1個10******;如果是1110***x(就是最左邊的0的左邊有3個1),代表後面還有2個10******;以此類推。很明顯,以11開頭的,最左邊的0左邊有多少個1,那這個ucs的utf-8的表示長度就有多少個位元組。

注意:在微軟window作業系統中,會給utf-8檔案新增bom【ef bb bf】(雖然不需要這麼做),這並不是說明utf-8需要位元組序,而是僅僅表名該檔案是utf-8編碼的檔案。

reference: 

有關ansi, ansi 不是一種編碼方式,而是使用字元編碼的約定。只有windows在使用。ansi的全稱是 america national standard institute(美國國家標準協會)。微軟在處理字元編碼時收集了各個國家定義個各種字元編碼集,如中國的gbk,台灣的big5,南韓的euc-kr,日本的shift_jis等等。每種編碼在系統中定義了乙個**頁(windows code page) 來表示,每個**頁被賦予乙個唯一的編碼,如gbk 的code page 是936。通過設定windows系統的region and language選項來指定系統當前使用的**頁。當windows 程式在處理編碼的時候可以通過當前活動**頁(active code page)呼叫相應的字元編碼。這是微軟解決系統本地化的方案。

從PDF說開去

最近想研究一下pdf。pdf從ps脫胎而來,秉承ps強大的描述能力,以其精美的 效果,已幾乎成為internet時代的 標準文件格式 說pdf是 標準 可能有人不愛聽,見後文 如果軟體能夠支援自動輸出 匯出 為pdf格式文件,無疑軟體的專業化色彩會更濃一些。人之常理 你推出一種文件格式,使用的人 軟...

從時間說開去

非常羨慕那種需要很少睡眠,思維敏捷,做事雷厲風行的人。之所以羨慕,是因為我不具備。我做為乙個需要很多睡眠並且睡眠質量不高的人,做事也一般是三思而後行,遇事也慢人半拍,對於我這樣乙個人,怎樣合理安排時間就成了很大的問題。從小就喜歡利用一大片的時間,專注的去做一件事情。所以,在上了大學以後,看到我的同學...

從「盜版」說開去

發行了幾年的共享軟體 vb原始碼之友 終於被盜版了,雖然共享軟體沒有給我帶來讓人羨慕的財富,但是這幾年來也有不少的正版使用者群在默默的支援著我繼續推出我的軟體產品。我的心情其實很複雜,但卻沒有憤怒,在我腦中揮之不去的卻是 盜火 英雄普羅公尺修斯的偉大形象。想想看,如果不是盜版,作為普通的個人使用者,...