Python 入門指南 5.0
單元 26 - 編碼
編碼 (encoding) 需要用到轉換表格,我們利用字串 (string) 儲存這個表格,簡單說,就是利用 Unicode 排列順序,對應到表格中該位置的字元
×
⇓
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
q | z | i | r | a | j | s | b | k | t | c | l | u | d | m | v | e | n | w | f | o | x | g | p | y | h |
上圖是用了如下的表格
| code ="qzirajsbktcludmvenwfoxgpyh"
|
我們先來想一想程式如何完成編碼工作,假設是對以下的字串進行編碼
| "There is no spoon."
|
首先, 'T' 不是英文小寫字母,因此跳過,然後 'h' 、 'e' 、 'r' 、 'e' 都是英文小寫字母,對照表格,需要轉換為 'b' 、 'a' 、 'n' 、 'a' ,接下來遇到一個空格字元 ' ' ,也跳過,然後 'i' 、 's' 也都是英文小寫字母,需要轉換為 'k' 、 'w' ,餘下類推。
所以需要利用一個迴圈 (loop) 進行上述編碼工作,逐一檢查字串中的每一個字元,若是屬於英文小寫字母的編碼範圍就是 Unicode 編碼 97 到 122 之間,我們先將該字元轉換為整數,然後減掉 97 就會是表格字串中對應字元索引值。
這是說,第 0 個字元(索引值為 0 ) 'T' 不在英文小寫字母編碼的範圍,因此程式不會處理,然後到第 1 個字元 'h' ,這是英文小寫字母編碼為 104 ,減去 97 之後為 7 ,對應到上面的表格會是 'b' ,因此得到的新字串第 1 個新字元就是 'b' ,餘下會一直進行重複的工作到字串結束為止。
因此,我們在 encrypt06.py 加入 toEncode() 的設計
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | # 使用標準程式庫中 random 的 randint()
from random import randint
# 定義 Encrypt 類別
class Encrypt:
# 定義建構子
def __init__(self):
# 建立密碼表
self.set_code()
# _code 的 getter
@property
def code(self):
return self.__code
# _code 的 setter
def set_code(self):
# 取得 a 、 b 值
a = 0
b = 0
while a % 2 == 0:
a = randint(0, 9)
b = randint(0, 9)
# 利用公式建立密碼表
self.__code = ""
c = "a"
i = 0
while i < 26:
x = c
y = ord(x) * a + b
m = y % 26
self.__code += chr(m + 97)
c = chr(ord(c) + 1)
i += 1
# 編碼的方法
def toEncode(self, str):
# 暫存編碼結果的字串
result = ""
# 利用迴圈走完參數字串的所有字元
for c in str:
# 判斷該字元是否為英文小寫字母
# 若是英文小寫字母就進行編碼轉換
c1 = ord(c) >= 97
c2 = ord(c) <= 122
if c1 and c2:
m = ord(c) - 97
result += self.code[m]
else:
result += c
# 結束回傳編碼過的字串
return result
# 解碼的方法
def toDecode(self, str):
pass
# 測試部分
if __name__ == '__main__':
e = Encrypt()
print()
print(e.code)
s1 = "There is no spoon."
print("Input : " + s1)
s2 = e.toEncode(s1)
print("Encode: " + s2)
print()
# 檔名: encrypt06.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月
|
toEncode() 接收一個字串 str 當參數 (parameter) ,也回傳一個新字串 result , str 就是要編碼的字串,而 result 則是編碼過的字串。
進行編碼轉換的迴圈
42 45 46 47 48 49 50 51 | for c in str:
c1 = ord(c) >= 97
c2 = ord(c) <= 122
if c1 and c2:
m = ord(c) - 97
result += self.code[m]
else:
result += c
|
這裡用 for 迴圈逐一取得 str 中每一個元素,也就是單一字元的子字串,然後判斷那一個字元是否是英文小寫字母,如果是就將該字元的 Unicode 編碼值減去 97 ,依此當密碼表的索引值,取得 code 中該索引值的字元附加到 result 的最後。
英文小寫字母 a 的 Unicode 值為整數 97 ,其後 b 、 c 、 d 等依次加 1 , Python 預設處理的是 Unicode 編碼, ASCII 相容於 Unicode ,因此就英文字母而言, Unicode 跟 ASCII 的值相同。
測試部分也加進了準備編碼的字串,然後印出編碼結果
62 63 64 65 66 67 68 69 | if __name__ == '__main__':
e = Encrypt()
print()
print(e.code)
s1 = "There is no spoon."
print("Input : " + s1)
s2 = e.toEncode(s1)
print("Encode: " + s2)
print()
|
執行結果如下
$ python encrypt06.py |
pyhqzirajsbktcludmvenwfoxg |
Input : There is no spoon. |
Encode: Tazmz jv cl vullc. |
$ |
接下來,我們繼續加入解碼的功能吧!
中英文術語對照 | |
---|---|
編碼 | encoding |
迴圈 | loop |
參數 | parameter |
字串 | string |
重點整理 |
---|
1. 轉換表格利用串列來儲存,每個元素都是長度為 1 的英文字母字串,可用索引值存取元素值。 |
2. 編碼時利用迴圈依序取得要編碼字串的所有字元,先判斷是否為英文小寫字母,如果是英文小寫字母就進行編碼,如果不是就直接把該字元附加到暫存變數的最後。 |
問題與討論 |
---|
1. 要怎麼判斷一個字元是英文小寫字母或大寫字母? |
2. 為什麼可以用對照表格的方式進行轉換? |
練習 |
---|
1. 寫一個程式 exercise2601.py ,承接單元 18 練習的座標 Point 類別與動物獅 Lion 類別,在命令列上印出 4×4 的鬥獸棋棋盤,並於 (1, 1) 的座標印出 Lion 實體。 參考程式碼 |
2. 承上題,將新程式寫在 exercise2602.py 中,將在棋盤上印出動物的方式放到函數 print_world() 中。 參考程式碼 |
3. 承上題,將新程式寫在 exercise2603.py 中,設定向右及向下的指令串列,再利用作業系統清空命令列的指令,例如 Windows 為 cls , Mac 或 Linux 為 claer ,以及標準程式庫 time 的 sleep() 函數暫停 1 秒製作動畫效果。 參考程式碼 |
4. 承上題,將新程式寫在 exercise2604.py 中,將清空命令列的程式碼部分整理成函數 clear_monitor() ,動物移動部分的程式碼整理成函數 move() 。 參考程式碼 |
5. 承上題,將新程式寫在 exercise2605.py 中,設計一個檢查動物是否出界的函數 bound_check() 。 參考程式碼 |
6. 承上題,將新程式寫在 exercise2606.py 中,進行隨機移動 10 步的模擬。 參考程式碼 |
7. 承上題,將新程式寫在 exercise2607.py 中,重新設計函數 print_world() ,讓 print_world() 可以印出多隻動物。 參考程式碼 |
8. 承上題,將新程式寫在 exercise2608.py 中,設計一個檢查移動座標是否有動物的函數 animal_check() 。 參考程式碼 |
9. 承上題,將新程式寫在 exercise2609.py 中,模擬兩隻獅子輪流各走十步。 參考程式碼 |
10. 承上題,將新程式寫在 exercise2610.py 中,加入互吃遊戲結束機制。 參考程式碼 |
11. 承上題,將新程式寫在 exercise2611.py 中,改成每一次執行都是隨機動物隨機移動。 參考程式碼 |