從字符編碼到python的字符串與bytes

最近編寫自己的rpc小框架,涉及到bytes.這裏就想梳理一下編碼與python的字符串和字節碼(bytes)類型.

 

先上個圖,有個印象,隨時可以回頭看.

 

# 前置知識

字符:在計算機和電信技術中,一個字符是一個單位的字形、類字形單位或符號的基本信息。即一個字符可以是一箇中文漢字、一個英文字母、一個阿拉伯數字、一個標點符號等;

字符集:多個字符的集合。例如GB2312是中國國家標準的簡體中文字符集;

字符編碼:將某個字符集中的字符轉換成一個唯一編號(碼點,二進制數據).於是同時,我們也可以根據字符編號找到對應字符集中的唯一字符。(專業點的比喻就是映射);
 

UTF編碼方案:

Unicode字符集轉換格式,即怎樣將Unicode定義的數字轉換成程序數據.

Unicode解決了字符和二進制的對應關係,但是使用unicode表示一個英文字符,太浪費空間。例如:利用unicode表示“Python”需要12個字節才能表示,比原來ASCII表示增加了1倍。

爲了解決存儲和網絡傳輸的問題,出現了Unicode Transformation Format,學術名UTF,即:對unicode中的格式進行轉換,以便於在存儲和網絡傳輸時可以節省空間.

同時爲了傳輸時的可靠性,從UNICODE到UTF時並不是直接的對應,而是要過一些算法和規則來轉換。

總結:UTF 是爲unicode編碼 設計 的一種 在存儲 和傳輸時節省空間的一系列編碼方案。

UCS:

對於Unicode來說,UCS是內碼是唯一編號,而UTF-8則是它的實現方式。

從字符經過字符集得到唯一編號的這個過程.就是USC.

UCS只是規定如何編碼,並沒有規定如何傳輸、保存這個編碼。UCS-2是2個字節保存內碼,UCS-4是4個字節保存內碼.

例如“漢”字的UCS編碼是6C49,我可以用4個ascii數字來傳輸、保存這個編碼;也可以用utf-8編碼:3個連續的字節E6 B1 89來表示它。關鍵在於通信雙方都要認可。UTF-8、UTF-7、UTF-16都是被廣泛接受的方案。UTF-8的一個特別的好處是它與ISO-8859-1完全兼容。UTF是“UCS Transformation Format”的縮寫。

 

位(bit):數據存儲的最小單位。每個二進制數字0或者1就是1個位;      0或1

字節(byte):8個位構成一個字節;即:1 byte (字節)= 8 bit(位);       0000,0000~1111,1111

python中的序列操作: 索引,切片,長度, 組合(序列相加)、重複(乘法),檢查成員,遍歷(迭代),最小值和最大值。

 

# Unicode 是啥

根據前置知識,我們可以猜到.ASCII,Unicode 指的是 字符集+字符編碼的組合.

ASCII字符集:128個 常用英文字符+常用符號

ASCII碼 : 一個字節    python中: 2個16進製表示此2進制數據 '\xc4\x80'    

Unicode字符集: 萬國碼,所有國家的字符.

Unicode碼 : 兩個字節    python中: 4個16進製表示此2進制數據 '\u7fd4'    

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

 

# python3中的字符串

字符串是 Python 中最常用的數據類型。我們可以使用引號( ' 或 " )來創建字符串。

python3 字符串是一個 Unicode碼點(內碼)組成的不可變序列,支持通用序列操作。可以看作是一個都是數字的元組.這個數字可以在Unicode字符集裏找到對應的字符.

Python2中,普通字符串是以1字節ASCII碼進行存儲的,而Unicode字符串則存儲爲2字節unicode字符串,這樣能夠表示更多的字符集。使用的語法是在字符串前面加上前綴 u。

 

# UTF-8 又是啥?

字符通過unicode編碼轉成了一個二進制編號數字, 哪怕英文字符也需要2個字節.

而原本ASCII編碼英文字符只需要一個字節.老美老歐不爽了,他們不用,unicode就沒法全球化.

這導致出現了 Unicode 的多種面向傳輸的二進制格式照顧老美老歐的情緒:

UTF-8(可變編碼格式,最爲重要),UTF-16,UTF-32編碼.

 

UTF-8:被定義爲將代碼點編碼爲1至4個字節(其中英文只耗費1個字節,中文3字節),兼容ASCII

UTF-8具體的表現形式爲:

  • 0xxxxxxx:單字節編碼形式,這和 ASCII 編碼完全一樣,因此 UTF-8 是兼容 ASCII 的;
  • 110xxxxx 10xxxxxx:雙字節編碼形式;
  • 1110xxxx 10xxxxxx 10xxxxxx:三字節編碼形式;
  • 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx:四字節編碼形式。

UTF-16:2個字節

UTF-32:4個字節

注:值得說明的是,雖然utf編碼對漢字使用3個字節,但即使對於漢字網頁,utf-8編碼也會比unicode編碼節省,因爲網頁中包 含了很多的英文字符。

 

# python3中的bytes

bytes對象是一個 0 <= x < 256 區間內的整數(一個字節)不可變序列。

 

# python3 字符串與bytes的區別

可能有人好奇,字符不特麼也是二進制嗎,不也是佔字節麼,python中字符串和bytes連操作都差不多,計算機萬物皆二進制啊.都在扯雞毛蛋呢,把人繞暈了不是.

字符串以,字符爲單位進行操作.

bytes由多個字節組成,以字節爲單位進行操作。

 

網絡傳輸中在socket這裏.是一個字節一個字節讀的.可能讀2個字節纔是一個字符.

bytes是面向傳輸的python對象

上面前置知識有一句:爲了傳輸時的可靠性. 可能內碼不方便傳輸?(待續..容我想想.....)

 

# python3 字符串與bytes的轉換

字符串編碼轉成bytes

b = a.encode(encoding='utf-8') # bytes

bytes解碼成字符串

c = b.decode(encoding='utf-8') # str

 

這裏再講一下GBK,爲什麼GBK看起來能直接編碼呢,它的字符集難道也是UNICODE?

UNICODE 在制訂時沒有考慮與任何一種現有的編碼方案保持兼容,這使得 GBK 與UNICODE 在漢字的內碼編排上完全是不一樣的,沒有一種簡單的算術方法可以把文本內容從UNICODE編碼和另一種編碼進行轉換,這種轉換必須通過查表來進行。

如果說unicode編碼成UTF-8是算過去的,unicode編碼成GBK就是一個個找過去的.

unicode碼點〉unicode字符集 〉字符〉GB2312字符集〉GBK碼點

str = "川普牛掰"
str_utf8 = str.encode("UTF-8")
str_gbk = str.encode("GBK")

print(str)
print("UTF-8 編碼:", str_utf8)
print("GBK 編碼:", str_gbk)
print("UTF-8 解碼:", str_utf8.decode('UTF-8', 'strict'))
print("GBK 解碼:", str_gbk.decode('GBK', 'strict'))

》〉》打印〉》〉》

川普牛逼
UTF-8 編碼: b'\xe5\xb7\x9d\xe6\x99\xae\xe7\x89\x9b\xe9\x80\xbc'
GBK 編碼: b'\xb4\xa8\xc6\xd5\xc5\xa3\xb1\xc6'
UTF-8 解碼: 川普牛逼
GBK 解碼: 川普牛逼

》〉》〉》〉》

 

 

 

未完待續,我再想想...

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章