最近編寫自己的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 解碼: 川普牛逼
》〉》〉》〉》
未完待續,我再想想...