Python字元編碼和二進位制不得不說的故事

北門吹雪發表於2020-10-03

二進位制

核心思想:
  馮諾依曼 + 圖靈機

  電如何表示狀態,才能穩定?
    計算機開始設計的時候並不是考慮簡單,而是考慮能自動完成任務與結果的可靠性,
    簡單始終是建立再穩定、可靠基礎上

    經過嘗試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

  

 

相關文章