Python 入門指南 5.0

單元 26 - 編碼

~~學習進度表~~

編碼 (encoding) 需要用到轉換表格,我們利用字串 (string) 儲存這個表格,簡單說,就是利用 Unicode 排列順序,對應到表格中該位置的字元

There is no spoon.
×                 

012345678910111213141516171819202122232425
qzirajsbktcludmvenwfoxgpyh

上圖是用了如下的表格

  
code ="qzirajsbktcludmvenwfoxgpyh"

我們先來想一想程式如何完成編碼工作,假設是對以下的字串進行編碼

  
"There is no spoon."

首先, 'T' 不是英文小寫字母,因此跳過,然後 'h''e''r''e' 都是英文小寫字母,對照表格,需要轉換為 'b''a''n''a' ,接下來遇到一個空格字元 ' ' ,也跳過,然後 'i''s' 也都是英文小寫字母,需要轉換為 'k''w' ,餘下類推。

所以需要利用一個迴圈 (loop) 進行上述編碼工作,逐一檢查字串中的每一個字元,若是屬於英文小寫字母的編碼範圍就是 Unicode 編碼 97122 之間,我們先將該字元轉換為整數,然後減掉 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) ,也回傳一個新字串 resultstr 就是要編碼的字串,而 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 ,以及標準程式庫 timesleep() 函數暫停 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 中,改成每一次執行都是隨機動物隨機移動。 參考程式碼

上一頁 單元 25 - 修正後的數學公式
回 Python 入門指南 5.0 首頁
下一頁 單元 27 - 解碼
回 Python 教材首頁
回程式語言教材首頁