Python字元編碼和二進位不得不說的故事
二進位
核心思想:
馮諾依曼 + 圖靈機
電如何表示狀態,才能穩定?
電腦開始設計的時候並不是考慮簡單,而是考慮能自動完成任務與結果的可靠性,
簡單始終是建立再穩定、可靠基礎上
經過嘗試10進位,但很難檢查電流的狀態差異並且很難穩定狀態,最穩定的檢查是
通電和不通電狀態,共兩種狀態那就規定 通電為 1 不通電 為 0,1和0的狀態邏
輯被稱為比特 Bit
那麼如何用 0 和 1 表示數字和字元呢?
首先找出需要表示的字元,英文字元和數字字元才100多個,需要 7 個二進位位就
可以全部表示,但為了可擴展性,多出一位表示擴展,這就是ASCII碼
因為一個字元只需要最多8個二進位位表示,所以規定8個位元組作為存儲單位,所有
8 Bit = 1 Byte
規定字元用數字表示,數字用二進位表示,也就是 字元 –> 數字 — > 二進位,
那麼文本資訊就可以通過電腦存儲為二進位,電腦上存儲的二進位數可以逆轉
成文本資訊
10 進位到二進位之間的關係轉換是固定的,那麼字元到數字之間的轉換被我們稱為
字元編碼, ASCII碼 Unicode UTF-8 都是存儲字元與數字之間的映射關係
弄清楚幾個關係
1. 字元與數字之間的關係為映射關係,人為規定的標準
這種映射關係,生活中普遍存在,如
a. 身份證資訊與身份證號碼
b. 資料庫id與該行資訊
c. 訂單資訊與訂單編號
d. 員工編號與員工
e. 字典的鍵與值
f. 記憶體地址與存儲在該地址上的值
…
2. 數字到二進位之間的關係,這個如同數學或物理定律一樣,固定轉換方式,寫死的
3. 8進位 16 進位都是建立在2進位的基礎上,和10進位之間沒有直接關係,主要為了
可讀性,二進位的兩種表示形式
如二進位 00000000 一個存儲單位,八進位000 000 000 每 3 個二進位位轉
換位10進位表示,最小數為 0 最大數為 7,所以取值範圍為 0 – 7
十六進位 0000 0000 每 4個二進位位轉換位10進位表示,最小位為0 最大為15,
所有取值範圍為 0 – 15,因為超出10機製表示範圍所以用 abcdef表示 10 11
12 13 14 15
十六進位常用於 記憶體地址表示 IPv6地址 顏色表 mac地址 二進位數據\x前綴b/B
IP地址(32位 點分十進位) x.x.x.x 每個x都是8個bit位表示的十進位數字
# 8進位 16進位是建立在二進位的基礎之上
Py進位轉換函數
10進位轉其他進位
轉2進位 bin 前綴0b
轉16進位 hex 前綴0x
轉8進位 oct 前綴0o
# 二進位 八進位 十六進位都是通過帶前綴的字元串形式”0b/o/x…”
# 10 進位轉其他進位 number = 9999 print("10進位轉其他進位".ljust(40, "*")) # 10 進位轉2進位 b_number = bin(number) print("二進位:", b_number) # 10進位轉8進位 o_number = oct(number) print("八進位:", o_number) # 10進位轉16進位 h_number = hex(number) print("十六進位:", h_number)
其他進位轉10進位 int(…, base) base指定進位
# 10 進位轉其他進位 number = 9999 print("10進位轉其他進位".ljust(40, "*")) # 10 進位轉2進位 b_number = bin(number) print("二進位:", b_number) # 10進位轉8進位 o_number = oct(number) print("八進位:", o_number) # 10進位轉16進位 h_number = hex(number) print("十六進位:", h_number) # 其他進位轉10進位 # 2進位轉10進位 num_b = int(b_number, base=2) print(num_b) # 8 進位轉10進位 num_o = int(o_number, base=8) print(num_o) # 8 進位轉16進位 num_h = int(h_number, base=16) print(num_h)
字元串轉二進位字元串
bytes
encode
需要指定字元編碼,結果前綴為 b/B”…”
# 字元串轉二進位字元串 song = "你驕傲的飛遠,我棲息的夏天" byte_song = song.encode(encoding="utf-8") print(byte_song) # 等價於 eq_byte_song = bytes(song, encoding="utf-8") print(eq_byte_song) print(byte_song == eq_byte_song)
二進位轉字元串
decode
str
需要指定字元編碼
# 二進位轉字元串 song = "你驕傲的飛遠,我棲息的夏天" # 獲得二進位數據 byte_song = song.encode(encoding="utf-8") print(byte_song) # 二進位字元串轉文本字元串 print("二進位數據轉字元串".rjust(40, "_")) dec_song = byte_song.decode(encoding="utf-8") print(dec_song) # 等價於' str_song = str(byte_song, encoding="utf-8") print(str_song) print(dec_song == str_song)
算術方法
10進位轉2 8 16進位,輾轉除法取餘數
其他進位轉10進位是從右往左加上基數的指定次方然後求和
# 轉換方式像公式定律,固定
二進位表示
分為有符號和無符號類型,一般是 8 16 32 64 Bit 表示整數或浮點數
有符號最高位表示符號,就是最左邊的比特位,0表示正1表示負數 正負下標位0和1
有符號位表示範圍,因為要分成兩半,一半表示正數一半表示負數,
說白了是去除一位表示符號位 -2**(n-1) – 2**n(n-1) -1, n = 8/16/32/64
無符號位表示 0到2**n -1
# 長度不一樣,分為1/2/4/8位元組
Py字元對應ASCII數字函數
ord()
字元編碼
語言文字 —> 數字 —> 0 1二進位
# 這個映射關係表被稱為字元編碼
# 字元編碼解決的問題是字元與十進位之間映射關係,人為定義的
中國 gb2312 -> GBK 中文2位元組,英文1個位元組
國際 Unicode(2-4個位元組) -> UTF-8(1-4個位元組)
1. 支援全球語言字元
2. 包含全球字元編碼映射
# 全球各國語言可以轉成Unicode,Unicode可以轉全球各個國家語言
3. 全球軟/硬體都支援Unicode
主流 UTF-8
因為Unicode表示一個字元需要至少2個位元組,那麼原來用ASCII只需要一個位元組,
現在使用Unicode編碼則存儲與進行網路傳輸需要的存儲空間直接翻倍,不可接受
UTF-8為了解決這個問題,於是走上了歷史舞台,那好,網路傳輸和存儲使用
UTF-8,作業系統支援Unicode,那麼高效傳輸、存儲和支援全球語言體系成為可能
Python中編碼
首先說說Python中編碼到底是何方神聖?
我們看存儲程式碼的文件和程式碼載入到記憶體然後被解釋器處理的文件
我們敲的程式碼,其實本質上是文本數據
文本數據要通過某一編碼表轉換成二進位然後存儲到硬碟上
存儲在電腦上的二進位數據也需要編碼表才能轉換成文本數據
Python中編碼是怎麼回事?
Py3中默認文件編碼為UTF-8, 我們通過編輯器編輯文件的時候也會有個默認編碼
一般默認為UTF-8,如果定義的文件中文本數據不是以UTF-8編碼,則需要在Py文
件的頭行告訴Py解釋器這個文件是以何種編碼。
解釋器讀取的並不是我們看到的編輯器裡面的文本數據,而是存儲在硬碟上的01
一樣的二進位數據,解釋器嘗試用默認UTF-8編碼解碼讀取到硬碟中的二進位數
據,轉換成文件數據,如果非默認utf-8則出現亂碼,解釋器對文本數據解析失敗,
則需要在Py源文件開頭指定當前文件的編碼格式,告訴Py解釋器如何去轉換該文件
Py解釋器默認編碼是Unicode,解釋器會把讀取到的二進位數據通過字元編碼轉
換成文件數據然後再次轉換為Unicode編碼,只要作業系統支援Unicode,解釋器
都能正常執行並輸出結果
解釋器
二進位數據 -> 查字元編碼表 -> 文本數據 -> Unicode編碼的文本數據
編輯器
二進位數據 -> 查字元編碼表 -> 對應編碼表的文本數據
# 解釋器和編輯器都是從文件的二進位數據開始的,通過編碼轉換成對應的文本
# 數據,不過解釋器會會在文件數據的基礎上解析文本數據成底層機器指令並執行
需要弄清楚的是Py源文件編碼和Py解釋器默認編碼不一致
# Py源文件編碼默認UTF-8,Py解釋器默認編碼為Unicode
那麼,產生亂碼的解決問題的思路就很好解決了
# 亂碼 – 字元編碼指定錯誤,存儲的二進位轉換成文本文件選擇的字符集錯誤
1. C/S 架構的軟體,檢查 Client 和 Server默認編碼是否一致
2. Web後端,資料庫默認編碼、表的編碼和各個語言連接資料庫介面的編碼是否一致
3. 文件,檢查編輯器的默認編碼是否和文件初始編碼一致,什麼編碼就存什麼編碼讀
Python聲明源文件字元編碼的方式
1. # conding:utf-8
2. # -*- conding:utf-8 -*-
# 都是以 # 開頭,寫在源文件頂行
# -*- coding:utf-8 -*- # coding: utf-8