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

上圖是用了如下的表格
| code = "qzirajsbktcludmvenwfoxgpyh" |
我們先來想一想程式如何完成編碼工作,假設是對以下的字串 (string) 進行編碼
| "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() 的設計
| 001 | # 使用 randint() |
| 002 | import random |
| 003 | |
| 004 | # 定義 Encrypt 類別 |
| 005 | class Encrypt: |
| 006 | def __init__(self): |
| 007 | self.setcode() |
| 008 | |
| 009 | def setcode(self): |
| 010 | # 取得 a 、 b 值 |
| 011 | a = 0 |
| 012 | b = 0 |
| 013 | while a % 2 == 0: |
| 014 | a = random.randint(0, 9) |
| 015 | b = random.randint(0, 9) |
| 016 | |
| 017 | # 利用公式建立密碼表 |
| 018 | self.code = "" |
| 019 | c = "a" |
| 020 | i = 0 |
| 021 | while i < 26: |
| 022 | x = c |
| 023 | y = ord(x) * a + b |
| 024 | m = y % 26 |
| 025 | self.code += chr(m + 97) |
| 026 | c = chr(ord(c) + 1) |
| 027 | i += 1 |
| 028 | |
| 029 | def getcode(self): |
| 030 | return self.code |
| 031 | |
| 032 | # 編碼的方法 |
| 033 | def toEncode(self, str): |
| 034 | # 暫存編碼結果的字串 |
| 035 | result = "" |
| 036 | |
| 037 | # 利用迴圈走完參數字串的所有字元 |
| 038 | for c in str: |
| 039 | # 判斷該字元是否為英文小寫字母 |
| 040 | # 若是英文小寫字母就進行編碼轉換 |
| 041 | c1 = ord(c) >= 97 |
| 042 | c2 = ord(c) <= 122 |
| 043 | if c1 and c2: |
| 044 | m = ord(c) - 97 |
| 045 | result += self.code[m] |
| 046 | else: |
| 047 | result += c |
| 048 | |
| 049 | # 結束回傳編碼過的字串 |
| 050 | return result |
| 051 | |
| 052 | # 解碼的方法 |
| 053 | def toDecode(self, str): |
| 054 | pass |
| 055 | |
| 056 | # 測試部分 |
| 057 | if __name__ == '__main__': |
| 058 | e = Encrypt() |
| 059 | print() |
| 060 | print(e.getcode()) |
| 061 | s1 = "There is no spoon." |
| 062 | print("Input : " + s1) |
| 063 | s2 = e.toEncode(s1) |
| 064 | print("Encode: " + s2) |
| 065 | print() |
| 066 | |
| 067 | # 檔名: encrypt06.py |
| 068 | # 作者: Kaiching Chang |
| 069 | # 時間: July, 2014 |
toEncode() 接收一個字串 str 當參數 (parameter) ,也回傳一個新字串 result , str 就是要編碼的字串,而 result 則是編碼過的字串。
進行編碼轉換的迴圈
| 037 | # 利用迴圈走完參數字串的所有字元 |
| 038 | for c in str: |
| 039 | # 判斷該字元是否為英文小寫字母 |
| 040 | # 若是英文小寫字母就進行編碼轉換 |
| 041 | c1 = ord(c) >= 97 |
| 042 | c2 = ord(c) <= 122 |
| 043 | if c1 and c2: |
| 044 | m = ord(c) - 97 |
| 045 | result += self.code[m] |
| 046 | else: |
| 047 | result += c |
基於編輯需求,避免單行程式碼過長造成版面錯誤,有些可合併為一行的程式碼會拆成兩、三行。
這裡用 for 迴圈逐一取得 str 中每一個元素,也就是單一字元的子字串,然後判斷那一個字元是否是英文小寫字母,如果是就將該字元的 Unicode 編碼值減去 97 ,依此當密碼表的索引值,取得 code 中該索引值的字元附加到 result 的最後。
測試部分也加進了準備編碼的字串,然後印出編碼結果
| 056 | # 測試部分 |
| 057 | if __name__ == '__main__': |
| 058 | e = Encrypt() |
| 059 | print() |
| 060 | print(e.getcode()) |
| 061 | s1 = "There is no spoon." |
| 062 | print("Input : " + s1) |
| 063 | s2 = e.toEncode(s1) |
| 064 | print("Encode: " + s2) |
| 065 | print() |
執行結果如下

接下來,我們繼續加入解碼的功能吧!
中英文術語對照
| 編碼 | encoding |
| 字串 | string |
| 字串 | string |
| 迴圈 | loop |
| 參數 | parameter |
重點整理
- 轉換表格利用串列來儲存,每個元素都是長度為 1 的英文字母字串,可用索引值存取元素值。
- 編碼時利用迴圈依序取得要編碼字串的所有字元,先判斷是否為英文小寫字母,如果是英文小寫字母就進行編碼,如果不是就直接把該字元附加到暫存變數的最後。
問題與討論
- 要怎麼判斷一個字元是英文小寫字母或大寫字母?
- 為什麼可以用對照表格的方式進行轉換?
練習
- 承接上一個單元的猜數字遊戲,將新程式寫在 exercise1801.py 中,在遊戲迴圈中利用內建函數 len() 檢查使用者輸入的長度,若是長度不等於 4 就印出提示訊息進行下一輪。。
- 承上題,將答案 answer 改成串列,並以 "0" 到 "9" 十個字串當元素,用標準模組庫中 random 的 shuffle() 攪亂順序後取得前四個元素當遊戲答案。
the end
沒有留言:
張貼留言