上圖是用了如下的表格
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'};
對以下的字串 (string) 而言
"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' ,餘下會一直進行重複的工作到字串結束為止。
因此,我們對編碼方法 (method) 設計如下
public String toEncode(String s) { char[] cs = s.toCharArray(); int i, ci, d, m; char r; String rs = ""; Character cc; // 進行編碼轉換 for (i = 0; i < cs.length; i++) { if (cs[i] >= 97 && cs[i] <= 122) { ci = cs[i]; m = ci - 97; cs[i] = getArray()[m]; } } // 將字元陣列儲存為字串 for (i = 0; i < cs.length; i++) { cc = new Character(cs[i]); rs = rs.concat(cc.toString()); } return rs; }
toEncode() 接收一個字串當參數,也回傳一個新字串。我們在 toEncode() 建立一個新字元陣列 cs ,這是因為字串被設計成不可變的 (immutable) ,也就是說,字串一旦被建立後,就不能再被更改內容,所以利用字串的 toCharArray() 方法,講字串轉換成字元陣列,然後指派給 cs ,這樣一來,我們便可以計算出結果後,直接將得到的結果設定給原來的陣列中相同的元素 (element) 。
進行編碼轉換的迴圈
// 進行編碼轉換 for (i = 0; i < cs.length; i++) { if (cs[i] >= 97 && cs[i] <= 122) { ci = cs[i]; m = ci - 97; cs[i] = getArray()[m]; } }
字元陣列的屬性 (field) length 為陣列中元素的個數,迴圈的控制變數 i 最大不超過 cs.length ,因為陣列索引從 0 開始,最後一個元素的索引為 length - 1 。留意這一行
cs[i] = getArray()[m];
getArray() 回傳我們的轉換表格 cArray ,因此這一行等同於
cs[i] = cArray[m];
最後我們還需要一個迴圈,用來把字元陣列逐一附加到字串內
// 將字元陣列儲存為字串 for (i = 0; i < cs.length; i++) { cc = new Character(cs[i]); rs = rs.concat(cc.toString()); }
同樣的,這個迴圈重複進行 cs.length 次。迴圈內的工作先以 Character() 將字元陣列中的字元 cs[i] 包裝成字元物件,這是因為基本資料型態 (primitive data type) 的字元與字元物件是不一樣的,基本資料型態直接是存在變數記憶體中的數值 (value) ,物件的變數記憶體儲存的是對物件的參考 (reference) 。
其實 Character() 就是字元物件的建構子 (constructor) ,這裡轉換為字元物件後,才可以利用字元物件的 toString() 方法,將字元物件轉換為字串。我們使用字串的 concat() 方法將參數附接到呼叫此方法的字串末端,而 concat() 需要以字串當參數,所以我們需要進行以上的型態轉換工作。
咦,不是說字串是不可變的嗎?這裡我們最初建立空字串變數 rs ,最後得到的結果同樣為變數 rs ,也回傳 rs 。的確,字串是不可變的,但是我們可以把字串的參考變數重新指向自己,也就是
rs = rs.concat(cc.toString());
道理很簡單,因為 rs.concat(cc.toString()) 會傳一個新字串,我們將 rs 重新當成這個新字串的參考,因此 rs 最初是空字串,進入這個迴圈後,字元陣列 cs 中的字元會逐一轉換為字串加進 rs 之中。
事實上,這過程會產生 cs.length 個字串,每個字串物件失去參考變數後,會被 Java 虛擬機器的資源回收者(garbage collector) 回收處理,然後釋放出原先分配的記憶體空間,所以程式可以有效執行,不會拖泥帶水造成系統的累贅。
我們只增加一個 toEncode() 方法,完整的 Encrypt 類別可以參考 Encrypt.java 。
EncryptDemo 需要修改,然後才可對 toEncode() 進行測試
// 測試 Encrypt 的類別 public class EncryptDemo { public static void main(String[] args) { System.out.println(); String s, t; s = "There is no spoon."; t = ""; for (int i = 0; i < 16; i++) { Encrypt e = new Encrypt(); t = e.toEncode(s); System.out.println(t); } System.out.println(); } } /* 《程式語言教學誌》的範例程式 http://pydoing.blogspot.com/ 檔名:EncryptDemo.java 功能:示範 Java 程式 作者:張凱慶 時間:西元 2011 年 4 月 */
我們只對 "There is no spoon." 進行編碼,總共 16 次,每一次採用不同的轉換表格。記得, Encrypt 與EncryptDemo 兩個類別都修改過,因此需要重新編譯,才可以執行出所要測試的程式碼喔!
接下來,我們繼續加入解碼的功能吧!
中英文術語對照 | |
---|---|
編碼 | encoding |
陣列 | array |
字串 | string |
迴圈 | loop |
字元 | character |
方法 | method |
不可變的 | immutable |
元素 | element |
屬性 | field |
基本資料型態 | primitive data type |
數值 | value |
參考 | reference |
建構子 | constructor |
資源回收者 | garbage collector |
您可以繼續參考
軟體開發
相關目錄
回 Java 入門指南
回 Java 教材目錄
回首頁
參考資料
The JavaTM Tutorials: Getting Started
The JavaTM Tutorials: Learning the Java Language
The JavaTM Tutorials: Essential Classes
The Java Language Specification, Third Edition
本文於 2013 年 1 月訂正
本文於 2013 年 2 月修正
4 則留言:
然後到第 1 個字元 'h' ,這是英文小寫字母編碼為 84
→ 應該是104吧?
這部份打錯了,已修改,感謝指正 :)
以下純屬實驗性質:
將2個for迴圈合併:
for(i=0; i< cs.length; i++){
if (cs[i]>=97 && cs[i]<=122){
m= cs[i]-97;
cs[i]=getArray()[m];
}
cc= new Character(cs[i]);
rs= rs.concat(cc.toString());
}
這樣是OK的,但若改成如下:
for(i=0; i< cs.length; i++){
if (cs[i]>=97 && cs[i]<=122){
m= cs[i]-97;
cs[i]=getArray()[m];
}
rs= rs.concat(cs[i]);
}
則會出現error:
The method concat(String) in the type String is not applicable for the arguments (char)
但我在for迴圈中用下式去查,二者是一樣的:
System.out.println(cs[i]);
System.out.println(cc);
請問,問題出在哪?
for迴圈合併,不能再精簡了嗎?
感謝指導!
cs[i] 的是基本資料型態的字元, cc 則是字元物件, concat() 的參數必須是字串物件,這裡是把字元先轉換成字元物件,然後再用 toString() 轉換成字串物件。如果要精簡的話,不妨可以改成直接用字串處理 :)
張貼留言