1 第 10 章 字串
2 字串的產生 其中 StringBuffer 與 StringBuilder 類別會在 10-3 節中介 紹。底下就來看看如何透過前 4 個建構方法產生字串: 這 是 個 測 試 字 串 4ED6 test 4ED6 test[0] test[1] test[2] test[3] test[4] test[5] test[6] 5F12 a 6124 b 這是個測試字串這是個測試字串 6255 c 測試字串測試字串 63EF d 這是個測試字串這是個測試字串 5F EF
3 字串的產生 5F12 a 6124 b 這是個測試字串這是個測試字串 6255 c 測試字串測試字串 63EF d 這是個測試字串這是個測試字串 5F EF
4 使用字面常數建立 String 物件 Java 對於 String 類別最重要的支援, 除了可以用 + 號來連接字串之外, 還可以使用字面常數來產生 String 物件, 例如: 執行結果 : 6124 b 這是一個測試字串這是一個測試字串 a 這是一個測試字串這是一個測試字串 64AC c 6124 b 這是一個測試字串這是一個測試字串 a c c 是建立副本, 指向另一個新物件。
5 使用字面常數建立 String 物件 其中第 4 行就是直接使用字面常數建立物件。當程式中有字 面常數時, Java 編譯器其實會產生一個 String 物件來代表所 有相同內容的字面常數字串。 也就是說, 第 5 行設定給 b 的參照值其實和給 a 的是一樣的, 都指向同一個 String 物件;而第 6 行傳給 String 類別建構方 法的也是同一個物件。 您可以把這 3 行看成是這樣: 6124 b 這是一個測試字串這是一個測試字串 constant a 這是一個測試字串這是一個測試字串 64AC c
6 使用字面常數建立 String 物件 6124 這是一個測試字串這是一個測試字串 64AC 6124 b a c 這是一個測試字串這是一個測試字串
7 自動轉型 (Implicit Conversion) Student name : String +Student(String) +toString() : String name +Student(String) +toString() : String 4F18 4ED6 a JOyJOy 4F18 相當於寫成 : a.toString
8 自動轉型 (Implicit Conversion) 要注意的是, toString() 方法必須傳回 String 物件, 而 且必須加上 public 存取控制。 ▪ 若是字串與基本資料型別的變數做連接運算, 則該變數 會被包裝成對應類別的物件, 再呼叫該類別的 toString() 方法, 詳見第 節。 int k = 20; System.out.println( “ k 值為 “ + k ); 會被包裝成 Integer 類別的物件
9 char charAt(int index) 這是一個測試字串這是一個測試字串 64AC 索引碼 a 物件名稱.charAt(int) 練習 : System.out.println( “ Test : ” + “ 大華技術學院 ”.charAt(5)); 這這
10 int compareTo(String anotherString) 以逐字元方式 (Lexically) 與 anotherString 所指字串 的內容比較, 如果 anotherString 比較大, 就傳回一個 負數值。 如果字串內容完全相同, 就傳回 0 ;如果 anotherString 比較小, 就傳回一個正數值。
11 int compareTo(String anotherString) abcdabcd a abcbabcb abcdabcd abcdabcd abcdeabcde abcdabcd AbcdAbcd abceabce 十進位代表字元 65A 66B …… 97a 98b 99c 100d Unicode 事實上, 在比較時是做兩個字母的 Unicode 相減的動作 。
12 int compareTo(String anotherString) 與 equals() 方法類似, compareTo() 方法也有一個雙 胞胎 compareToIgnoreCase(), 在比較時會將同一 字母大小寫視為相同。 練習 : 將上述程式第 6 行下面加上以下兩敘述 : System.out.println(a.compareTo( “ ABCD ” )); System.out.println(a.compareToIgnoreCase( “ ABCD ” ));
13 boolean contains(CharSequence s) 傳回字串中是否包含有 s 所指字串的內容在裡頭。 練習 : 將上述程式第 8 行下面加上以下兩敘述 : System.out.println(a.contains( “ acd ” )); System.out.println(a.contains( “ ABCD ” ));
14 boolean endsWith(String suffix) 傳回是否以指定的字串內容結尾。 練習 : 將上述程式第 5 行下面加上以下兩敘述 : System.out.println(a.endsWith( “ abcd ” )); System.out.println(a.endsWith( “ D ” ));
15 void getChars(int srcBegin, int srcEnd, char[ ] dst, int dstBegin) 將索引碼 srcBegin 到 srcEnd - 1 的字元, 複製到 dst 所指字元陣列、由索引碼 dstBegin 開始的元素中。 srcBegin : source begin 來源開始 srcEnd : source end 來源結束 dst : destination 目的 dstBegin : destination begin 目的開始 這是一個測試字串這是一個測試字串 索引碼 a a chars Chars[0] Chars[1] Chars[2] Chars[3] 練習 : 試改成 System.out.println( chars ) ; 是 一 個 測 複製複製 chars Chars[2] Chars[3]
16 int indexOf(int ch) 傳回 ch 所指定的字元在字串中第一次出現位置的索 引碼, 如果字串中未包含該字元, 就傳回 -1 。 這是一個測試字串這是一個測試字串 索引碼 a
17 int indexOf(int ch) 這個方法有個雙胞胎的版本, 叫做 lastIndexOf(), 可 以從字串尾端往前尋找。 練習 : 將上述程式第 4 行改成 : String b = “ 這是一個個測試字串 ”; 第 6 行下面加上以下敘述 : System.out.println(b.lastIndexOf( ‘ 個 ’ )); 這是一個個測試字串這是一個個測試字串 索引碼 b 8
18 int indexOf(int ch, int fromIndex) indexOf() 方法的多重定義版本, 可以透過 fromIndex 指定開 始尋找的位置。 只要結合這 2 種 indexOf() 方法, 就可以逐一找出字串中所有 出現指定字元的位置了。 這個方法也有個雙胞胎的版本, 叫做 lastIndexOf(), 可以從字 串尾端往前尋找。 練習 : 將上述改過的程式最後加上以下敘述 : System.out.println(b.indexOf( ‘ 個 ’,2)); System.out.println(b.lastIndexOf( ‘ 個 ’,6)); 這是一個個測試字串這是一個個測試字串 索引碼 b 8
19 int indexOf(String str) indexOf() 的多重定義版本, 尋找的是指定字串出現的 位置。 這是一個測試字串這是一個測試字串 索引碼 a 找不到 ” 字符 ”
20 int indexOf(String str) 這個方法也有個雙胞胎的版本, 叫做 lastIndexOf(), 可 以從字串尾端往前尋找。 練習 : 將上述程式最後加上以下敘述 : String b = “ 這是一個一個測試字串 ” System.out.println(b.lastIndexOf( “ 一個 ” )); 這是一個一個測試字串這是一個一個測試字串 索引碼 a 8 9
21 int indexOf(String str, int fromIndex) indexOf() 方法的多重定義版本, 可以透過 fromIndex 指定開始尋找的位置。 只要結合這 2 種 indexOf() 方法, 就可以逐一找出所有出現指定字串的位置 了。 當然也有個對應的 lastIndexOf() 方法, 可以從字串尾端往前尋找。 練習 : 將上述程式最後加上 : String b = “ 這是一個一個測試字串 ”; System.out.println(b.indexOf( “ 一個 ”,1 )); System.out.println(b.lastIndexOf( “ 一個 ”,7 )); System.out.println(b.indexOf( “ 一個 ”,5)); 這是一個一個測試字串這是一個一個測試字串 索引碼 b 8 9
22 int length() 傳回字串的長度。 這是一個一個測試字串這是一個一個測試字串 索引碼 b 練習 : 將上述程式最後加上 : System.out.println(b.length()); 10 char[] a = new char[10]; System.out.println(a.length); 屬性 方法
23 String replace(char oldChar, char newChar) 將字串中所有出現 oldChar 所指定的字元取代為由 newChar 所指定的字元。 要提醒您的是, 這並不會更改原始字串的內容, 而是將 取代的結果以新的字串傳回。 這是一個測試字串這是一個測試字串 索引碼 a 考 練習 : 修改此行敘述為 String a = “ 這是一個測試測字串 “;
24 String replace(CharSequence target, CharSequence replacement) 和上一個方法功能類似, 但是將字串中所有出現 target 所指字串內容的地方都取代為 replacement 所 指字串的內容。 這是一個測試字串這是一個測試字串 索引碼 a 正式正式
25 boolean startsWith(String prefix) boolean startsWith(String prefix, int offset) startsWith() 的用法和前面看過的 endsWith() 類似, 但功能相反, startsWith() 是用來檢查目前字串是否是 以參數字串 prefix 開頭。 較特別的是 startsWith() 有兩個參數的版本, 可指定從 索引位置 offset 開始, 檢查是否以參數字串 prefix 為 開頭。
26 boolean startsWith(String prefix) boolean startsWith(String prefix, int offset) abcdabcd 索引碼 a
27 String substring(int beginIndex) 傳回由 beginIndex 所指定索引開始到結尾的子字串。
28 String substring(int beginIndex, int endIndex) 傳回由 beginIndex 所指定的索引碼開始到 endIndex - 1 所指定的索引碼為止的部分字串。 這是一個測試字串這是一個測試字串 索引碼 a
29 String toLowerCase() 傳回將字串中的字元轉成小寫後的副本。 練習 : 將上述程式最後加上 : String b = “ AbcdE ”; System.out.println(b.toLowerCase());
30 String toUpperCase() 將字串中的字元全部轉為大寫。 練習 : 將上述程式最後加上 : System.out.println ( “ AbcdE ”. toUpperCase());
31 String trim() 將字串中頭、尾端的空白符號去除,包含空白字元、 定位字元等等。 △ 用一個 代表一個 空白。 △ △△△ … △
32 String trim() ▪ 以上這些方法都經常會用到, 也是應考的重點。 練習 : 將上述程式第 5 行改成 : System.out.println (“ 測試 ” + a.trim() + “ trim() 方法 ” );
33 StringBuffer 類別 這是一個測試字串這是一個測試字串 索引碼 a 這是一個測試字串這是一個測試字串 b
34 StringBuffer 類別 還記得在 10-5 頁提過, Java 會產生一個 String 物件 來代替程式中的字面常數, 所以第 4 、 5 行也可直接寫 成: 以下就來介紹 StringBuffer 類別的修改字串方法, 這 些方法不但會直接修改 StringBuffer 物件的內容, 也 會將修改後的結果傳回。 String a = “ 這是一個測試字串 ”; StringBuffer b = new StringBuffer(a) ;
35 append() 方法 append() 方法擁有多重定義的版本, 可以傳入基本型別、 String 物 件以及其他有定義 toString() 方法的物件。 a 這是一個測試字串 20 字串內容已經變了 b 這是一個測試字串 20 字串內容已經變了 20 字串內容已經變了 a 這是一個測試字串 20 a 這是一個測試字串
36 insert() 方法 insert() 方法和 append() 方法一樣有多種版本 ( Ref. ), 但是它可以透過第 1 個參數 offset 將 第 2 個參數插入到字串中的特定位置。 offset 代表的是索引碼, insert() 方法會把資料插入 到 offset 所指的位置之前。 這是一個測試字串 b a 索引碼
37 insert() 方法 在第 11 行可以看到, 如果第 1 個參數傳入字串的長 度, 就等於是 append() 了。 a 這是一個測試字串 7 5 索引碼 這是一個測試字串 b 這字串內容已經變了是一個測試字串 20 b 這字串內容已經變了是一個測試字串 20 b b 17 索引碼 18 這字串內容已經變了是一個測試字串 20
38 StringBuffer delete(int start, int end) delete() 方法可以刪除由 start 所指定索引碼開始到 end - 1 所指定索引碼之間的一段字元。 a 這是一個測試字串 b 7 索引碼 b 這一個測試字串 索引碼 相當於 b.deleteCharAt(1) ( 參考下一張投影片 )
39 StringBuffer deleteCharAt(int index) 刪除由 index 所指定索引碼的字元。
40 StringBuffer replace(int start, int end, String str) 將 start 所指定索引碼開始到 end - 1 所指定索引碼之 間的一段字元取代為 str 所指定的字串。 b 這是一個測試字串 索引碼 b 這是個測試字串 索引碼 取代
41 StringBuffer reverse() 將整個字串的內容頭尾反轉。例如: 串字試測 測試字串
42 void setCharAt(int index, char ch) 將 index 所指定索引碼的字元取代成 ch 所指定的字 元。 請特別注意, 這是唯一一個更改了字串內容, 但卻沒有 傳回自己的方法, 在使用時要特別小心。
43 void setCharAt(int index, char ch) b 這是一個測試字串 索引碼 二
44 甚麼是規則表示法 str 123D
45 甚麼是規則表示法 十進位代表字元 47/ …… : …… 65A …… 68D Unicode str 123D 索引碼
46 甚麼是規則表示法 str 123D 索引碼
規則表示法入門 為了讓大家可以直接練習, 所以我們先撰寫了一個測 試的程式, 可以讓您直接輸入樣式以及要比對的字串, 並顯示出比對的結果是否相符:
48 規則表示法入門 pat print 索引碼 1 2 str 索引碼 1 2 print Print ( 輸入樣式 ) ( 輸入字串 )
49 限制出現次數 除了剛剛使用過的 "+" 以外, 規則表示法中還可以使 用如下常用的次數限制規則 ( 量詞 ) : 出現兩次
50 字元種類 (Character Classes) 您也可以用中括號來表示一組字元, 比如說: 其中樣式 [bjl] 表示此位置可以出現 'b' 或 'j' 或 'l', 因此 "a[bjl]a" 這個樣式的意思就是先出現一個 'a', 再出現一個 'b' 或 'j' 或 'l ', 再接著一個 'a' 。 在第 2 個執行結果中, 因為輸入的字串第 2 個字元並非 'b' 或 'j' 或 'l', 所以不相符。
51 字元種類 (Character Classes) 您也可以在中括號中使用 "-" 表示一段連續的字碼區 間, 比如說上一小節使用過的 [0-9] 就包含了數字, 而 [a-z] 則包含了小寫的英文字母, [A-Z] 則包含了大寫 的英文字母, [a-zA-Z] 就是所有的英文字母了:
52 字元種類 (Character Classes) 這個範例的樣式表示先出現一個 ' a ', 然後接著數字 或是英文字母, 再接著一個 'a', 所以第 2 個執行結果 因為有 '#' 而不相符。 另外, 您也可以在左中括號後面跟著一個 '^', 排除中 括號中的字元, 例如: Not Not (a 到 z) 非小寫英文字母
53 預先定義的字元種類 (Character Class) 由於數字或是英文字母 之類的規則很常會用到, 因此規則表示法中預先 定義了一些字元種類, 如 右所示: ▪ 由於句號代表任意字元, 原來的句號則需以 \. 表 示。 (digit) (space)
54 預先定義的字元種類 (Character Class) 第 2 個執行結果因為第 2 個字元 'b' 不是數字而不相 符。 (digit) (space)
55 範例
56 群組 (Grouping) 您也可以使用括號將一段規則組合起來, 搭配限制次 數使用, 例如: (digit) (space)
57 以字面常數指定樣式 如果要在程式中以字面常數指定樣式, 由於 Java 的編 譯器會將 '\' 視為跳脫序列的啟始字元 ( 例如 \t 表定位 字元、 \n 表換行字元、 \\ 代表 \ 字元 ), 因此要使用預 先定義的字元種類時, 就必須在前面多加一個 '\', 以便 讓 Java 編譯器將 '\' 視為一般的字元, 例如: (digit) (space)
58 如果寫成這樣: 編譯時就會認為 '\d' 是一個不合法的跳脫序列。 以字面常數指定樣式
replaceAll ( ) 方法 規則表示法除了可以用來比對字串以外, 也可以用來 將字串中符合指定樣式的一段文字取代成另外一段文 字, 讓您可以極富彈性的方式進行字串的取代, 而不是 僅能使用簡單的 replace() 方法。 為了簡化, 我們將剛剛的 RegExTest.java 修改, 以方 便測試 replaceAll() 方法:
60 replaceAll ( ) 方法 pat 111 src a111bc34d ( 輸入樣式 ) ( 輸入字串 ) rep 三個一 ( 輸入取代字串 )
61 使用樣式進行取代 replaceAll() 最大的用處是可以使用規則表示法, 例 如: 這裡搜尋的樣式是 "\d+", 所以字串中的 "111" 以及 "34" 都符合這個樣式, 都會被取代為 " 數字 " 。 src a111bc34d ( 輸入字串 ) pat \d+ ( 輸入樣式 ) rep 數字 ( 輸入取代字串 ) src a111bc34d
62 使用群組 有時候我們會希望取代的結果要包含原來被取代的那段文 字, 這時就可以使用群組的功能, 例如: 其中要取代成 " 數字 $1" 中的 "$1" 的意思就是指比對相符 的那段文字中, 和樣式中第 1 個群組相符的部分。以本例 來說, 當 "111" 與 "(\d+)" 比對相符時, 第一個群組就是 "(\d+)", 與這個群組相符的就是 "111" 這段文字, 所以取代 後的結果變成 " 數字 111" ;相同的道理, 後面比對出 "34" 時, 就取代為 " 數字 34" 了。
63 使用群組 依此類推, $2 、 $3 、... 自然是指第 2 、 3 、.... 個群組了, 至於 $0 則是指比對出的整段文字, 例如: 規則表示法的功能非常強大, 詳細的說明可以參考 JDK 的說明文件。
64 split( ) 方法 s Ken+Sue+Tom\0 練習 : 將以上敘述的 ” [+m] ” 全改為 ” [+] ” 。 s Ken+Sue+Tom\0 規則表示法的樣式, 代表碰到 ” + ” 或 ” m ” 就要切割。 aa[0] 7F6E7F8C a[1] Ken Sue+Tom\0 結束字元, 每一個字串都有此一字元在最後, 此為空字串, 代表字串的結束 。 Ken Sue+Tom\0 Ken Sue+Tom\0 Ken Sue+Tom\0 Ken Sue To \0 aa[0] a[1]a[2] a[3] s 7F8C Ken 7F8C Sue+Tom\0 Ken 7F8C 7F6E s 7F8C
65 10-A 檢查身份證字號的格式
66 10-A 檢查身份證字號的格式 要使用預先定義的字元種類時, 就必須在前 面多加一個 '\', 以便讓 Java 編譯器將 '\' 視 為一般的字元。 str
67 10-B 檢核身份證字號
68 10-B 檢核身份證字號, 若差值為 10, 則身分證字號檢查碼為 0, 若為 1 至 9 的數字, 則身分證字號檢查碼即為該數字。 身分證字號最後一碼為檢查碼, 下 述方法就是如何利用檢查碼前面的 英文字母與數字求出其檢查碼。
69 10-B 檢核身份證字號 檢查身分證字號的格 式, 此部分的程式與 CheckIDFormat.java 完全相同。 letterNums[0][1] ……19…… letterNums [2] [3][10][21][22][23][24] [25] str Z 索引碼 Z K 練習 : 在此段程式中 加入「檢查英文字母 後一位數字不可以 是 ” 1 ” ( 代表男生 ) 或 ” 2 ” ( 代表女生 ) 的數字」。
70 10-B 檢核身份證字號 ……19…… letterNums str letterNums[0][1] [2] [3][10][21][22][23][24] [25] Z 索引碼 Z 十進位代表字元 …… …… 65A 66B …… 75K …… 89Y 90Z Unicode x x x x x x x x x x total ( 檢查碼 ) checkNum = (10 – 170 % 10) % 10 0