我們打算開始發展一個 Encrypt 類別,它的主要功能是建立一個英文小寫字母的對換表格,藉由這個表格,我們可以對英文句子中的小寫英文字母進行對換,例如 "There is no spoon." 可能變成以下任一個
Tfqdq ki jo itooj.
Tcnan hf gl fqllg.
Tczmz dn ij nkjji.
Tgfsf pb ir barri.
Tdcpc my fo yxoof.
其中, EncryptDemo 類別為我們在命令列 (command line) 對 Encrypt 進行測試的類別,然後,最重要的是我們還要發展使用者介面 (user interface) 的類別,給使用者輕鬆操作的圖形使用者介面 (graphical user interface, GUI) ,也就是 EncryptGUI 類別,我們會直接在 EncryptGUI 中設置 Main() 方法,因此 EncryptGUI 可直接執行。
這裡把建立對換表格的工作交給 Encrypt ,使用者的 GUI 介面的設計交給 EncryptGUI 。 EncryptDemo 為命令列的測試程式, EncryptGUIDemo 中同樣建立 Encrypt 物件,但有更多功能,外觀如下圖
有兩個可供輸入的文字欄位 (textfield) ,其中一個我們作為輸出的顯示訊息之用,另有三個標籤 (label) ,顯示文字的提示訊息,七個按鈕 (button) ,提供「新建」、「開啟」、「儲存」 Encrypt 物件,與「編碼」、「解碼」所輸入的英文句子,「清除」所有輸入欄位,以及「拷貝」輸出結果等的功能。
為什麼要設計這麼多的類別,不把所有功能塞進一個類別就好了呢?寫個 Main() ,然後把所有程式碼塞進 Main() 當中,同樣可以達到我們想要的程式。理由其實很單純,我們大可發展一個功能完備可在命令列大展神威的 Encrypt ,可是換在 GUI 中,很多細節必須重新設計,幾乎等於重寫,因此我們把功能與使用者介面分開來,實際編碼、解碼的工作交給 Encrypt ,因此命令列使用 EncryptDemo 操作,可直接利用 Encrypt , GUI 由 EncryptGUI 設計,也可重複利用 Encrypt ,這樣一來,我們就不需要為命令列版本與 GUI 版本重複寫進相同的 Encrypt 程式碼。
事實上, .net 中許多類別都是基於這樣的理念設計的,一個類別專心做好一件事情就好 :)
現在我們先來看看 Encryptor 所有功能的核心,也就是 Encrypt 類別,我們的目的是,建立一個小寫英文字母的轉換表格,然後編碼、解碼都可直接依據這個表格。首先,我們先來看看建立表格的數學公式
y = a * x + b
m = y % n
r = m + diff
我們的概念很簡單,假設 x 為字元的原始編碼, Unicode 編碼中 'a' 為 97 ,其後依次遞增 1 ,然後我們將 x 乘上變數 (variable) a , 再加上變數 b ,兩者均是 0 到 9 的隨機整數,這樣便得到 y 的值。
然後將 y 除以 n 取得餘數 m , n 為所要轉換的字元數量,英文小寫字母共有 26 個,所以這裡 n 等於 26 ,因此 m 等於 0 到 25 之間的整數值。最後將 m 加上 diff , diff 也就是編碼系統的差值,由於 Unicode 中 'a' 為 97 ,所以這裡 diff 要以 97 代入。
因此,餘數 0 的字元會替換成 'a' ,餘數 1 的字元會被替換成 'b' ,餘數 2 的字元會被替換成 'c' ,餘下 23 個字元類推。這樣的計算需要進行 n 次,也就是 26 次,我們最後得到一組餘數與相對應字元的表格,這就是我們需要的表格了。
重複 n 次,我們需要一個迴圈 (loop) ,由於重複次數確定,因此 for 迴圈 (for loop) 很適合,那我們要用什麼東西來儲存這個表格呢?嗯, .net 中有許多的資料結構 (data structure) ,可以依資料特性有效率的處理資料,這裡,我們利用字串 (string) 就可以了。
字串是一種字元陣列 (array) ,陣列是固定大小的資料結構,當宣告陣列後,同時需要宣告陣列的型態與大小,也就是說,陣列最多可以放進多少個元素 (element) ,這些元素必須是相同的資料型態,而且,陣列的的索引值由 0 開始,因此完全符合我們計算餘數從 0 開始的需求。
因此, Encrypt 需要以下的屬性 (property)
string cArray;
這裡僅需要建立一個供 Encrypt 裡各個方法 (method) 存取的 cArray , cArray 儲存的正是密碼表。
我們先設置一個 setArray() 方法來測試,公式中需要用到的值,如整數 a 、 b 、 n 與 diff 等,這些都放在 setArray() 方法中當區域變數 (local variable) 。 a 先設成 3 , b 設成 5 好了
public void setArray() { int a = 3; int b = 5; int x, y, m; char c = 'a'; int i; System.Text.StringBuilder s = new System.Text.StringBuilder(); for (i = 0; i < 26; i++) { x = c; y = x * a + b; m = y % 26; s.Append((char) (m + 97)); c++; } this.cArray = s.ToString(); }
區域變數可以說是計算過程中所需要的暫存變數,也就是我們不會在其他地方存取或使用的變數,這些變數單獨在方法裡宣告、建立即可。
setArray() 有幾個觀念需要解釋,首先
x = c;
屬性 c 是 char 字元型態,而 x 為整數型態,這裡將字元型態的值指派給整數型態的變數,那麼 x 中得到的會是字元的 Unicode 的 Unicode 編碼值,由於 c 已經指派初值為 'a' ,因此 x 會是整數 97 。然後我們用到一個新的類別 StringBuilder
System.Text.StringBuilder s = new System.Text.StringBuilder();
由於字串建立後無法變更其內容,因此我們拿專門用來建立字串的 StringBuilder 當暫存變數,所以
s.Append((char) (m + 97));
計算完成後便用 StringBuilder 的 Append() 方法將字元附加到 s 的最後,這裡要注意小括弧圍著 char 是強制型態轉換的方式,由於 m 及 97 都是整數 int 型態,經過小括弧的強制型態轉換,會將 (m + diff) 轉換為字元 char 型態,例如,如果 m 等於 0 , 0 + 97 等於 97 ,那麼最後 'a' 會附加到 s 之中。
最後用 ToString() 方法,將 s 的字串格式指派給 cArray
this.cArray = s.ToString();
這裡用到 this , this 為關鍵字 (keyword) 之一,在類別中用來存取屬性與方法。
我們先寫一個簡單的程式來看看轉換後的表格長怎麼樣吧!
// Encrypt 的測試類別 // 使用 y = 3 * x + 5 class Encrypt { string cArray; public void setArray() { int a = 3; int b = 5; int x, y, m; char c = 'a'; int i; System.Text.StringBuilder s = new System.Text.StringBuilder(); for (i = 0; i < 26; i++) { x = c; y = x * a + b; m = y % 26; s.Append((char) (m + 97)); c++; } this.cArray = s.ToString(); } static void Main() { Encrypt e = new Encrypt(); e.setArray(); System.Console.WriteLine("e: " + e.cArray); } } /* 《程式語言教學誌》的範例程式 http://pydoing.blogspot.com/ 檔名:encrypt00.cs 功能:示範 C# 程式 作者:張凱慶 時間:西元 2012 年 10 月 */
編譯後執行,結果如下
結果如預期,一個英文小寫字母恰恰好對到另一個英文小寫字母,這樣我們的公式就 ok 了嗎?嗯, a 與 b 都可以是 0 到 9 之間的任意整數,有 100 種組合說,所以,我們需要繼續測試是不是每一種組合都 ok 囉!
中英文術語對照 | |
---|---|
程式 | program |
類別 | class |
物件 | object |
命令列 | command line |
使用者介面 | user interface |
圖形使用者介面 | graphical user interface, GUI |
textfield | 文字欄位 |
標籤 | label |
按鈕 | button |
變數 | variable |
迴圈 | loop |
for 迴圈 | for loop |
資料結構 | data structure |
字串 | string |
陣列 | array |
元素 | element |
屬性 | property |
方法 | method |
區域變數 | local variable |
關鍵字 | keyword |
您可以繼續參考
軟體開發
相關目錄
回 C# 入門指南
回 C# 教材
回首頁
參考資料
http://msdn.microsoft.com/zh-tw/library/ms173109%28v=vs.80%29.aspx
http://msdn.microsoft.com/zh-tw/library/x9afc042.aspx
http://msdn.microsoft.com/zh-tw/library/ms229036%28v=vs.80%29.aspx
http://msdn.microsoft.com/zh-tw/library/0b0thckt.aspx
2 則留言:
謝謝分享!
另外main()裡面e.setcArray應為setArray ^__^
這邊打錯字了,已修改,感謝指正 ^_^
張貼留言