C# 入門指南
單元 18 - 編碼
編碼 (encoding) 需要用到轉換表格,我們利用字串 (string) 儲存這個表格,簡單說,就是利用 Unicode 排列順序,對應到表格中該位置的字元
×
⇓
0 | 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 |
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 |
上面是用了如下的表格
code_array = "qzirajsbktcludmvenwfoxgpyh"
我們先來想一想程式如何完成編碼工作,假設是對以下的字串進行編碼
"There is no spoon."
首先, 'T' 不是英文小寫字母,因此跳過,然後 'h' 、 'e' 、 'r' 、 'e' 都是英文小寫字母,對照表格,需要轉換為 'b' 、 'a' 、 'n' 、 'a' ,接下來遇到一個空格字元 ' ' ,也跳過,然後 'i' 、 's' 也都是英文小寫字母,需要轉換為 'k' 、 'w' ,餘下類推。
所以需要利用一個迴圈 (loop) 進行上述編碼工作,逐一檢查字串中的每一個字元 (character) ,若是屬於英文小寫字母的編碼範圍就是 Unicode 編碼 97 到 122 之間,我們先將該字元轉換為整數,然後減掉 97 就會是表格字串中對應字元索引值。
這是說,第 0 個字元(索引值為 0 ) 'T' 不在英文小寫字母編碼的範圍,因此程式不會處理,然後到第 1 個字元 'h' ,這是英文小寫字母編碼為 104 ,減去 97 之後為 7 ,對應到上面的表格會是 'b' ,因此得到的新字串第 1 個新字元就是 'b' ,餘下會一直進行重複的工作到字串結束為止。
因此,我們對 ToEncode() 的設計如下
// 編碼方法
public string ToEncode(string s)
{
// 建立暫存字串
string result = "";
char c;
int m;
// 逐一取得字元進行處理
for (int i = 0; i < s.Length; i++)
{
// 判斷是否為英文小寫字母
if (s[i] >= 97 && s[i] <= 122)
{
c = s[i];
m = c - 97;
result += code[m];
}
// 不是英文小寫字母,直接將字元附加到 result 之後
else
{
result += s[i];
}
}
// 回傳結果
return result;
}
ToEncode() 接收一個字串 s 當參數 (parameter) ,也回傳一個新字串 result , s 就是要編碼的字串,而 result 則是編碼過的字串。
進行編碼轉換的迴圈
// 逐一取得字元進行處理
for (int i = 0; i < s.Length; i++)
{
// 判斷是否為英文小寫字母
if (s[i] >= 97 && s[i] <= 122)
{
c = s[i];
m = c - 97;
result += code[m];
}
// 不是英文小寫字母,直接將字元附加到 result 之後
else
{
result += s[i];
}
}
字串的屬性 Length 回傳字串長度,也就是字串中所有字元的總數,迴圈的控制變數 (control variable) i 最大不超過 s.Length() ,因為字串索引從 0 開始,最後一個元素的索引為 s.Length - 1 。
留意這一行
result += code[m];
字串可以跟加號與等號連在一起用,這樣可以把 code[m] 的字元附加到 result 的最後。這裡我們最初建立空字串變數 result ,最後得到的結果同樣為變數 result ,也回傳 result 。我們用的技巧是把字串的變數重新指向自己,因此這裡是用 += 運算子。
道理很簡單,因為 result += code[m] 會得到一個新字串,我們將 result 重新當成這個新字串的變數,因此 result 最初是空字串,進入這個迴圈後,無論 code[m] 或是 s[i] 都會加進 result 的最後,這時候產生的新字串會重新指派給 result 。
完整程式如下
using System;
namespace EncryptDemo06
{
class EncryptDemo06
{
// 宣告密碼表欄位
public string code;
// 建構子,呼叫建立密碼表的 SetCode() 方法
public EncryptDemo06()
{
SetCode();
}
// 建立密碼表
public void SetCode()
{
// 宣告變數
int a, b, x, y, m;
char c = 'a';
// a 、 b 初始化
Random r = new Random();
a = 0;
b = 0;
// a 不能是 0 或偶數
while (a % 2 == 0)
{
a = r.Next(1, 10);
}
b = r.Next(0, 10);
code = "";
// 建立密碼表的迴圈
for (int i = 0; i < 26; i++)
{
x = c;
y = x * a + b;
m = y % 26;
code += Convert.ToChar(m + 97);
c++;
}
}
// 編碼方法
public string ToEncode(string s)
{
// 建立暫存字串
string result = "";
char c;
int m;
// 逐一取得字元進行處理
for (int i = 0; i < s.Length; i++)
{
// 判斷是否為英文小寫字母
if (s[i] >= 97 && s[i] <= 122)
{
c = s[i];
m = c - 97;
result += code[m];
}
// 不是英文小寫字母,直接將字元附加到 result 之後
else
{
result += s[i];
}
}
// 回傳結果
return result;
}
// 解碼方法
public string ToDecode(string s)
{
return s;
}
}
class Program
{
static void Main(string[] args)
{
// 建立密碼物件
EncryptDemo06 e = new EncryptDemo06();
// 印出密碼表
Console.WriteLine(e.code);
// 建立測試字串
string s1 = "There is no spoon.";
// 印出測試字串
Console.WriteLine(s1);
// 進行編碼
string s2 = e.ToEncode(s1);
// 印出編碼結果
Console.WriteLine(s2);
}
}
}
//《程式語言教學誌》的範例程式
// http://kaiching.org/
// 專案:EncryptDemo06
// 檔名:Program.cs
// 功能:示範利用 C# 設計 Encrypt 類別
// 作者:張凱慶
執行部分改成先印出密碼表,然後建立測試字串,接著編碼測試字串,最後印出編碼結果
static void Main(string[] args)
{
// 建立密碼物件
EncryptDemo06 e = new EncryptDemo06();
// 印出密碼表
Console.WriteLine(e.code);
// 建立測試字串
string s1 = "There is no spoon.";
// 印出測試字串
Console.WriteLine(s1);
// 進行編碼
string s2 = e.ToEncode(s1);
// 印出編碼結果
Console.WriteLine(s2);
}
執行結果如下
C:\EncryptDemo06> dotnet run |
gnubipwdkryfmtahovcjqxelsz |
There is no spoon. |
Tdivi kc ta chaat. |
C:\EncryptDemo06> |
接下來,我們繼續加入解碼的功能吧!
相關教學影片
中英文術語對照 | |
---|---|
字元 | character |
控制變數 | control variable |
編碼 | encoding |
迴圈 | loop |
參數 | parameter |
字串 | string |
參考資料 | |
---|---|
1. C# 程式設計手冊 | Microsoft Docs - 類別 |
重點整理 |
---|
1. 轉換表格利用字串來儲存,字串可用索引值存取元素,也就是字元。 |
2. 編碼時利用迴圈依序取得要編碼字串的所有字元,先判斷是否為英文小寫字母,如果是英文小寫字母就進行編碼,如果不是就直接把該字元附加到暫存變數的最後。 |
3. 加號運算子在字串型態被多載過,可用於字串連結並且重新指派。 |
問題與討論 |
---|
1. 要怎麼判斷一個字元是英文小寫字母或大寫字母? |
2. 多載的意義是什麼?為什麼運算子可以多載? |
練習 |
---|
1. 承接上一個單元的猜數字遊戲,將新專案寫在 Exercise1801 中,在遊戲迴圈中檢查使用者輸入的長度,若是長度不等於 4 就印出提示訊息進行下一輪。 |
2. 承上題,將新專案寫在 Exercise1802 中,替 Guess 類別增加建構子,並且在建構子中設定三個欄位 answer 、 a 、 b 的初值。 |