C# 入門指南 - 編碼

編碼 (encoding) 需要用到轉換表格,我們利用字串 (string) 儲存這個表格,字串屬於字元陣列 (array) ,字元陣列中每個元素都是 Unicode 字元,簡單說,就是利用 Unicode 排列順序對應到表格的關係




上圖是用了如下的表格
cArray = {'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'};


對以下的字串而言
"There is no spoon.";


我們先來想一想程式應該如何完成這一項工作,首先, 'T' 不是英文小寫字母,因此跳過,然後 'h' 、 'e' 、 'r' 、 'e' 都是英文小寫字母,對照表格,需要轉換為 'b' 、 'a' 、 'n' 、 'a' ,接下來遇到一個空格字元 ' ' ,也跳過,然後 'i' 、 's' 也都是英文小寫字母,需要轉換為 'k' 、 'w' ,餘下類推。


所以需要利用一個迴圈 (loop) 進行上述編碼工作,逐一檢查字串中的每一個字元 (character) ,若是屬於英文小寫字母的編碼範圍,在 Unicode 就是 97 到 122 之間,先將該字元轉換為整數,然後減掉 97 就會是表格中對應字元的 Unicode 編碼值。


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


因此,我們對編碼方法 (method) 設計如下
public string toEncode(string s) {
    System.Text.StringBuilder r = new System.Text.StringBuilder();
            
    // 進行編碼轉換
    char c;
    int i, m;
    for (i = 0; i < s.Length; i++) { 
        if (s[i] >= 97 && s[i] <= 122) {
            c = s[i];
            m = c - 97;
            r.Append(this.Code[m]);
        }
        else {
            r.Append(s[i]);
        }
    }
            
    // 回傳字串
    return r.ToString();
}


toEncode() 接收一個字串當參數,也回傳一個新字串。我們在 toEncode() 建立一個暫存的 StringBuilder ,這是因為字串被設計成不可變的 (immutable) ,也就是說,字串一旦被建立後,就不能再被更改內容,所以藉由可變的 StringBuilder 來進行這項工作,最後再回傳字串。


進行編碼轉換的迴圈
// 進行編碼轉換
char c;
int i, m;
for (i = 0; i < s.Length; i++) { 
    if (s[i] >= 97 && s[i] <= 122) {
        c = s[i];
        m = c - 97;
        r.Append(this.Code[m]);
    }
    else {
        r.Append(s[i]);
    }
}


字串的屬性 (property) Length 為字串中元素的個數,迴圈的控制變數 i 最大不超過 s.Length ,因為陣列索引從 0 開始,最後一個元素的索引為 Length - 1 。留意這一行
if (s[i] >= 97 && s[i] <= 122) {


只有英文小寫字母,也就是 Unicode 字元編碼在 97 到 122 之間,才會進行編碼轉換。底下第一個動作
c = s[i];


由 c 取得 s 中的元素,然後
m = c - 97;


m 為該字元為第幾個英文字母,這可直接對應到表格,因此用 m 取得表格中的元素,亦即要轉換的字元
r.Append(this.Code[m]);



若非英文小寫字母,也就是 Unicode 字元編碼在 97 到 122 之外,就直接將該字元加進 r 之中
r.Append(s[i]);


完整的 Encrypt 修改如下
class Encrypt {
    private string cArray;
    
    public string Code {
        get { return cArray; }
        set { 
            if (value is string && value.Length == 26) {
                cArray = value; 
            }
            else {
                System.Console.WriteLine("something worng!!");;
            }
        }
    } 
        
    public Encrypt() {
        System.Random r = new System.Random();
        int a = 0;
        int b = 0;
        // 限定 a 為偶數
        while (a % 2 == 0) {
            a = r.Next(1, 10);
            b = r.Next(1, 10);
        }
        System.Console.Write("a: " + a + ", b: " + b + ", "); 
            
        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();   
    }
    
    public string toEncode(string s) {
        System.Text.StringBuilder r = new System.Text.StringBuilder();
            
        // 進行編碼轉換
        char c;
        int i, m;
        for (i = 0; i < s.Length; i++) { 
            if (s[i] >= 97 && s[i] <= 122) {
                c = s[i];
                m = c - 97;
                r.Append(this.Code[m]);
            }
            else {
                r.Append(s[i]);
            }
        }
            
        // 回傳字串
        return r.ToString();
    }
    
    static void Main() {
        string s = "There is no spoon.";
        for (int i = 0; i < 16; i++) {
            Encrypt e = new Encrypt();
            System.Console.WriteLine(i + ": "+ e.toEncode(s));
            System.Threading.Thread.Sleep(1000);
        }
    }
}

/* 《程式語言教學誌》的範例程式
    http://pydoing.blogspot.com/
    檔名:encrypt.cs
    功能:示範 C# 程式 
    作者:張凱慶
    時間:西元 2012 年 10 月 */


我們只對 "There is no spoon." 進行編碼,總共 16 次,每一次採用不同的轉換表格。測試結果如下



接下來,我們繼續加入解碼的功能吧!


中英文術語對照
編碼encoding
字串string
陣列array
迴圈loop
字元character
方法method
不可變的immutable
屬性property


您可以繼續參考
軟體開發


相關目錄
回 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

沒有留言: