Python 入門指南 V2.00 - 單元 18 - 編碼




編碼 (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 編碼 97122 之間,我們先將該字元轉換為整數,然後減掉 97 就會是表格字串中對應字元索引值。


這是說,第 0 個字元(索引值為 0'T' 不在英文小寫字母編碼的範圍,因此程式不會處理,然後到第 1 個字元 'h' ,這是英文小寫字母編碼為 104 ,減去 97 之後為 7 ,對應到上面的表格會是 'b' ,因此得到的新字串第 1 個新字元就是 'b' ,餘下會一直進行重複的工作到字串結束為止。


因此,我們在 encrypt06.py 加入 toEncode() 的設計


001# 使用 randint()
002import random
003
004# 定義 Encrypt 類別 
005class 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# 測試部分
057if __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) ,也回傳一個新字串 resultstr 就是要編碼的字串,而 result 則是編碼過的字串。


進行編碼轉換的迴圈


037# 利用迴圈走完參數字串的所有字元
038for 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# 測試部分
057if __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. 轉換表格利用串列來儲存,每個元素都是長度為 1 的英文字母字串,可用索引值存取元素值。
  2. 編碼時利用迴圈依序取得要編碼字串的所有字元,先判斷是否為英文小寫字母,如果是英文小寫字母就進行編碼,如果不是就直接把該字元附加到暫存變數的最後。


問題與討論


  1. 要怎麼判斷一個字元是英文小寫字母或大寫字母?
  2. 為什麼可以用對照表格的方式進行轉換?

練習


  1. 承接上一個單元的猜數字遊戲,將新程式寫在 exercise1801.py 中,在遊戲迴圈中利用內建函數 len() 檢查使用者輸入的長度,若是長度不等於 4 就印出提示訊息進行下一輪。。
  2. 承上題,將答案 answer 改成串列,並以 "0""9" 十個字串當元素,用標準模組庫中 randomshuffle() 攪亂順序後取得前四個元素當遊戲答案。

the end

沒有留言: