2014年3月18日 星期二

Java 複習筆記 : 字串

最近從圖書館借了幾本 Java 書來複習, 我是跳著看, 挑重點看 (字串與陣列), 因為做資料處理最重要的是字串與陣列的使用, 以下是關於字串的心得摘要筆記 :

# http://docs.oracle.com/javase/7/docs/api/java/lang/String.html

一. 字串的宣告與賦值 :

Java 的字串宣告方式 :

String str;

宣告之後其初始值跟陣列等物件變數一樣是 null (沒有指向任何字串實體). 也可以宣告同時賦值, 賦值的方式有兩個 :

  1. String str="abc";
  2. String str=new String("abc");

第一種方法是直接以 Literal (實體) 賦值; 而第二種則是以 String() 建構子賦值, 使用方式完全一樣, 但是其內在運作卻不同. 第一種方式賦值的字串變數會被放進字串池 (String Pool) 中, 這是 Java 編譯器為了減少記憶體耗損而設計的字串實體共享機制, 當有新的變數也使用此方法賦值時, Java 會去字串池中找一下有沒有相同內容的字串, 有的話就把這個新的字串變數參考指到這個已存在的字串, 例如 :

String str1="abc";
String str2="abc";

這兩個變數 str1 與 str2 事實上都指向字串池中相同的字串實體. 使用 "==" 這個參考的比較運算子去比較兩者, 答案會是 true (但這個 true 不是直接指兩者內容相同, 而是參考相同, 當然間接意義上也是因為內容相同) :

System.out.println(str1==str2);   //輸出 true

意思是, 這兩個變數參考都指向相同位址, 亦即指向字串池中的同一字串實體.

但如果使用 String() 建構子來賦值, 因為 new 的意思就是要在記憶體中新建一個字串實例, 所以會指配一個新的參考位址, 不會指配字串池中相同內容字串之參考位址. 當使用 "==" 去比較其參考時會得到 false :

String str1=new String("abc");
String str2=new String("abc");
System.out.println(str1==str2);   //輸出 false

下面這個例子也是輸出 false, 證明只要 new, 就不會使用字串池共享機制了 :

String str1="abc";
String str2=new String("abc");
System.out.println(str1==str2);   //輸出 false

剛開始學 Java 時會感到納悶, 這裡明明字串內容相同, 用 "==" 去比較卻得到 false, 因為這個運算子在 Java 中是用來比較物件 (參考) 的, 與 Javascript 的比較內容用法不同.

二. 字串內容的比較 :
Java 字串特性中一個最常讓人誤解的運算就是比較運算子 "==", 從上面說明可知, 這個運算子是用來比較兩個物件 (參考) 是否相同, 不是用來比較字串內容的. 在 Java 中比較字串要使用 String 物件的 equals(), compareTo(), 或 compareToIgnoreCase() 方法  :

String str1="abc";
String str2=new String("abc");
String str3=new String("aBc");
System.out.println(str1.equals(str2));   //輸出 true
System.out.println(str1.equals(str3));   //輸出 false
System.out.println(str2.equals(str3));   //輸出 false

可見字串內容相同時, equals 傳回 true, 否則傳回 false. 而 compareTo() 則是依據字元編碼數值大小, 從頭逐一比對字串中的字元, 若所有字元編碼均相同就傳回 0, 也就是字串內容完全一樣, 若物件本身字元編碼較大就傳回正整數, 否則傳回負整數 :

String str1="abc";
String str2=new String("abc");
String str3=new String("aBc");
System.out.println(str1.compareTo(str2));   //輸出 0
System.out.println(str2.compareTo(str3));   //輸出 32
System.out.println(str3.compareTo(str2));   //輸出 -32

所以 equals() 與 compareTo() 主要的差別是傳回值, 前者為 boolean, 後者為 int. 在此例中因為 B 的 ASCII 字元編碼為 66, 而 b 的編碼為 98, 所以 str2 與 str3 的差值就是 32. 如果要忽略大小寫進行比對, 則應該使用 compareToIgnoreCase() :

String str1="abc";
String str2=new String("abc");
String str3=new String("aBc");
System.out.println(str1.compareToIgnoreCase(str3));   //輸出 0
System.out.println(str2.compareToIgnoreCase(str3));   //輸出 0
System.out.println(str3.compareToIgnoreCase(str2));   //輸出 0

三. 字串內容是唯讀, 不可變更的 (immutable) :

這也是讓 Javascript 程式員感到很不習慣的地方, 例如 :

String str="abc";
str="123";
System.out.println(str);   //輸出 123

瞧, 這不是改變了字串內容了嗎? 怎麼說不可變更呢? 事實上, 第一個指令中 str 參考指向字串池中 "abc" 實體, 但第二個指令卻把 str 指向了 "123", 所以並非 str 字串的內容被改變了, 而是建立了新的字串物件 "123", 並將 str 參考指向這個新的物件 "123". 現在字串池中有兩個字串物件了, 其中 "abc" 已經無變數參考它, 將會被 Java 的垃圾回收機制給銷毀. 即使以 new String() 來建立字串, 其內容也是無法改變的. 所以 String 類別的方法全部都是 getter 方法, 沒有 setter 方法.


String str="0123456789";
System.out.println(str.length());               //輸出 10 (注意 length 是方法, 不是屬性)
System.out.println(str.indexOf("5"));        //輸出 5 (有找到傳回索引位置)
System.out.println(str.indexOf("a"));        //輸出 -1 (沒找到傳回 -1)
System.out.println(str.replace("5", "f"));   //輸出 01234f6789 (參數只限字元)
System.out.println(str.charAt(5));            //輸出 5
System.out.println(str.substring(5));         //輸出 56789 (直到字串尾)
System.out.println(str.substring(5, 9));     //輸出 5678
System.out.println(str.concat("abc"));      //輸出 012345678abc (串接在後)
System.out.println(str.startsWith("12"));   //輸出 true (參數是字串)
System.out.println(str.endsWith("12"));    //輸出 false (參數是字串)
str="abc";
System.out.println(str.toUpperCase());    //輸出 ABC
str="ABC";
System.out.println(str.toLowerCase());    //輸出 abc
str="ABC   ";
System.out.println(str.trim());                  //輸出 "ABC" (刪除尾端空白字元)

事實上, Java 的字串內容實際上是使用字元陣列 char[] 來存放的, 所以我們可以呼叫 charAt(int index) 方法來傳回指定位置的字元 :

String str="abc";
System.out.println(str.charAt(1));   //輸出 b

String 類別提供 toCharArray() 方法來傳回這個 char[] 陣列 :

String str="abc";
char[] arr=str.toCharArray();
for (int i=0; i  System.out.println(arr[i]); 

輸出 :
a
b
c

Java 的陣列長度宣告後就無法改變, 所以字串的內容當然就不能改變了. 在 String 類別的原始碼中, 這個儲存字串的字元陣列 values[] 被宣告為 final, 呼應了陣列的特性 :

private final char values[]

四. StringBuffer 與 StringBuilder 

Java 的字串無法更改內容在資料處理時會有困擾, 例如當我們要在字串中, 分別刪除許多不同之子字串時, 以迴圈來處理時, 每刪除一個子字串, 就要把刪除後的結果存起來, 以便下一個迴圈處理, 但這個暫存動作, 在 Java 而言事實上是新增一個字串物件, 若為 1000 次迴圈, 就會產生 1000 個字串物件, 將消耗許多記憶體.

StringBuffer (同步, 多執行緒) 與 StringBuilder (非同步, 單執行緒) 類別就是用來處理可變內容字串的. Java 的字串為何會分成可變更與不可變更兩種, 據書上講, 原因是 Java 支援多執行緒, 這時要用 StringBuffer 才能避免同步問題, 但單執行緒時應該用 StringBuilder, 其效率比 StringBuffer 高. 除此之外, 這兩者使用方式完全一樣. 如果字串內容不會改變, 當然用 String 類別就可以了, 它的執行效率最高.


要建立可變內容字串物件必須使用 StringBuffer() 或 StringBuilder() 建構子, 不像 String 那樣還可以用 Literal 方式.

StringBuffer sb=new StringBuffer("abc");

建構子預設會配置字串長度 + 16 個字元來儲存字串, 所以上面這指令會配置 3+16=19 個字元.

StringBuffer 常用的字串內容修改方法有 append(), insert(), delete(), deleteCharAt(), replace(), setCharAt(), 以及 reverse(), 都會傳回 StringBuffer 物件, 不須指定給原變數名稱, 而且 sb 的內容直接就被修改了 :

StringBuffer sb=new StringBuffer("123");
System.out.println(sb.append("abc"));  //輸出 123abc
System.out.println(sb.insert(2,"abc"));  //輸出 12abc3abc
System.out.println(sb.delete(2,5));       //輸出 123abc
System.out.println(sb.deleteCharAt(3));        //輸出 123bc
System.out.println(sb.replace(3,4,"45"));       //輸出 12345
System.out.println(sb.reverse());                   //輸出 54321

注意, 含有範圍參數的 delete((int start, int end) 與 replace(int start, int end, String str), 其真正作用的結束字元索引是參數 end-1.

StringBuffer 也提供 substring() 與 toString() 方法以傳回子字串或完整字串 :

StringBuffer sb=new StringBuffer("123abc");

System.out.println(sb.toString());        //輸出 123abc
System.out.println(sb.substring(2,4));  //輸出 3a

同樣的, substring(int start, int end), 其真正作用的結束字元索引是參數 end-1. 

五. 字串拆成陣列 :

Java 的 String 類別有一個 split() 方法, 可以把字串以傳入之子字串為界, 拆成一個字串陣列傳回, 這在 Javascript 也有相同的方法, 字串處理時很常用 :
String str="a:b:c";
String[] arr=str.split(":"); //拆成 {"a","b","c"} 陣列了.
for (int i=0; i<arr.length; i++) {
  System.out.println(arr[i]);
  }

輸出 :
a
b
c

六. 陣列元素串成字串 :  


在 Javacript 的陣列方法中, 有一個 join() 方法, 可以把一個字串陣列以傳入之字串為接合器, 將每一個元素串接成一個字串傳回, 例如 arr.join(","), 但可惜 Java 的陣列並無此方法, 需自行製作, 因為只用在單執行緒, 故可以用 StringBuilder 來製作如下 :

 public static String join(String[] arr) {
    return join(arr, ",");
    }
 public static String join(String[] arr, String g) {
    if (arr.length==0) {return "";}
    else {
      StringBuilder sb=new StringBuilder();
      sb.append(arr[0]);
      for (int i=1; i<arr.length; i++) {
        sb.append(g).append(arr[i]);
        }
      return sb.toString();
      }
    }

這裡用方法多載模擬 Javascript 中預設接合器為 "," 情況.

如果用 String 來實作, 雖然功能正確, 但當陣列元素多時將耗費很多記憶體 :

  public static String join(String[] arr, String g) {
    if (arr.length==0) {return "";}
    else {
      String str=arr[0];
      for (int i=1; i<arr.length; i++) {
        str += g + arr[i];
        }
      return str;
      }
    }


七. 字串取代 :

String 類別提供的 replace() 方法只能替換指定索引位置的字元, 而非字串. 替換字串必須使用 replaceFirst() 與 replaceAll() 這兩個方法, 但都必須使用正規表達式作為第一參數 :

String replaceFirst(String regex, String replacement)
String replaceAll(String regex, String replacement)

replaceFirst() 只取代第一筆符合的子字串, 而 replaceAll() 則是全部符合的子字串都要取代, 相當於 Javascript 裡的 g (Global) 的作用.

下面就以 replaceAll 來實作 VBscript 中的 ltrim (刪除左邊空格), rtrim(刪除右邊空格), 以及 trim (刪除左右邊空格) 的功能 :

  public static String ltrim(String str) {
    return str.replaceAll("^\\s+","");
    }

其中正規表達式 "^\\s+" 意思是找尋以一個以上的空白字元開始的子字串, 其中左斜線必須重複以跳脫 (escape). 然後用空字串取代, 這樣就可以刪除字串開頭的空白. 這裡用 replaceFirst 也可以.

注意, 我們這裡說的空白, 不只是空格 (white space) , 還包括水平定位(tab), 跳頁(form-feed) 與換列 (linefeed) 等不可見字元, 相當於正規式之 [\f\n\r\t\v\u00A0\u2028\u2029].

至於 rtrim(), 這是刪除字串右端任何空白字元之意, 因此要這麼寫 :

  public static String rtrim(String str) {
    return str.replaceAll("\\s+$","");
    }


$ 表示字串結束, 也就是以一個以上空格結束之意.

若要刪除開始與結束兩邊的空白, 其實 Java 的 String 類別已經提供了 trim() 方法, 跟 VBscript 的 trim() 是一樣的, 因此可以直接用它來實作 :

  public static String rtrim(String str) {
    return str.trim();
    }

 若用 RegExp 實作則要這麼寫 :

  public static String trim(String str) {
    return str.replaceAll("^\\s+|\\s+$","");
    }

"|" 符號表示或的意思, 因此不論開頭或結尾的空格都會匹配.

    System.out.println(rtrim("123  ").length());     //輸出 3
    System.out.println(ltrim("   123").length());     //輸出 3
    System.out.println(trim("   123   ").length());   //輸出 3

可見前後空格都被刪除了, 因此字串長度均為 3. 下列是較完整的範例 :

import java.util.*;
public class mytest {
  public static void main(String[] args) {
    String str=" abc def ";
    System.out.println("-" + trim(str) + "-");    //輸出 -abc def-
    System.out.println("-" + ltrim(str) + "-");    //輸出 -abc def -
    System.out.println("-" + rtrim(str) + "-");    //輸出 - abc def-
    System.out.println("-" + str.trim() + "-");   //輸出 -abc def-
    }
  public static String trim(String str) {
    return str.replaceAll("^\\s+|\\s+$","");
    }
  public static String rtrim(String str) {
    return str.replaceAll("\\s+$","");
    }
  public static String ltrim(String str) {
    return str.replaceAll("^\\s+","");
    }
  }

可見此處實作的 trim() 與 String 類別的 trim() 方法功能是一樣的, 用 "-" 串接就比較清楚左右空格是否被刪除了. 注意, trim/ltrim/rtrim 只對付字串左右邊界上的空白, 不會去除中間的空白

跟 Javascript 以 /g 表示 Global 不同, Java 的 Global 是用不同的方法 replaceFirst() 與 replaceAll() 分別處理, 但不管是 replaceFirst() 或 replaceAll() 都是預設有分大小寫的, 如果要不分大小寫, 則正規式要以 (?i) 開始, 例如 :

    String str="abcABCaBc";
    System.out.println(str.replaceAll("abc",""));                   //輸出 ABCaBc (分大小寫)
    System.out.println(str.replaceAll("ABC",""));                //輸出 abcaBc (分大小寫)
    System.out.println(str.replaceAll("(?i)(abc)","123"));     //輸出 123123123 (不分大小寫)
    System.out.println(str.replaceAll("(?i)(ABC)","$1-"));   //輸出 abc-ABC-aBc- (不分大小寫)

也可以用 Pattern 與 Matcher 類別搭配 Pattern.CASE_INSENSITIVE 常數來做, 不過須先匯入 Pattern 與 Matcher 這兩個類別 :

import java.util.regex.*;

然後再分別建立物件 :

    String str="abcABCaBc";
    Pattern p1=Pattern.compile("abc");
    Pattern p2=Pattern.compile("abc",Pattern.CASE_INSENSITIVE);
    Matcher m1=p1.matcher(str);
    Matcher m2=p2.matcher(str);
    System.out.println(m1.replaceAll(""));
    System.out.println(m1.replaceAll(""));
    System.out.println(m2.replaceAll("123"));
    System.out.println(m2.replaceAll("-"));

這樣似乎比較囉唆, 用 replaceFirst() 或 replaceAll() 不更方便?

再來看看跟 VB 的 trim/ltrim/rtrim 很像的 strip/lstrip/rstrip, 這是來自 Python 的好用方法, 基本上也是預設去除左右兩邊的空白, 不同的地方是, strip/lstrip/rstrip 還可以指定要刪除的字元集合, 而且 刪除指定子字串時, 是將其打散為字元作為匹配對象, 亦即它並非只是刪除子字串而已, 而是刪除該子字串的每一個字元. 例如 :

>>> str="<fooooo>fooobar</fooooo>"
>>> str.lstrip("<foo>")
'bar</fooooo>'
>>> str.rstrip("<foo>")
'<fooooo>fooobar</'
>>> str.strip("<foo>")
'bar</'

可見 Python 的 strip/lstrip/rstrip 是在字串開頭或結尾搜尋指定字元集合, 匹配者即刪除. 注意, 傳入的參數雖然是字串, 但它們是字元集合, 亦即 Python 不是將其視為 prefix 或 suffix 字串, 而是將其打散為字元後, 再去字頭或字尾搜尋. 這在 Java 要怎麼實作呢? 

首先來看 lstrip(), 參考下列 Python 功能描述 :

# https://docs.python.org/2/library/stdtypes.html 

"Return a copy of the string with leading characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a prefix; rather, all combinations of its values are stripped."

它舉的例子是 :

>>> "www.example.com".lstrip("cmowz.")
'example.com'


可見開頭含有 'c','m','o','w','z','.' 這六個字元組合者均會被刪除, 但中間 example 的 m 就不會. 因此正規表示法可寫成 :

^[cmowz.]+ 

亦即要用字元類別, 而且必須使用量詞 + (出現一次或多次), 範例如下 :

public class mytest {
  public static void main(String[] args) {
    String str=" www.example.com";  //注意開頭字元為空格

    System.out.println(lstrip(str));      //輸出 "www.example.com"  (刪除左端空格)
    str="www.example.com";            
    System.out.println(lstrip(str,"cmowz.")); 
//輸出  "example.com"
    }
  public static String lstrip(String str) {
    return str.replaceAll("^\\s+","");
    }
  public static String lstrip(String str, String chars) {
    return str.replaceAll("^[" + chars + "]+","");
    }
  }


可見與 Python 輸出一樣. 此處我們用方法多載處理傳入一個或二個參數情形. 而 rstrip() 也是同樣方式, 只是匹配位置改為字尾, 它給的例子是 :

>>> '   spacious   '.rstrip()
'   spacious'
>>> 'mississippi'.rstrip('ipz')
'mississ'


預設無參數時刪除左端的空白, 有參數時則刪除左端匹配的字元集.

範例如下 :

public class mytest {
  public static void main(String[] args) {
    String str="   spacious   ";
    System.out.println(rstrip(str));       
//輸出 "   spacious"
    str="mississippi";
    System.out.println(rstrip(str,"
ipz")); //輸出 "mississ"
    }
  public static String rstrip(String str) {
    return str.replaceAll("\\s+$","");
    }
  public static String rstrip(String str, String chars) {
    return str.replaceAll("[" + chars + "]+$","");
    }
  }


可見預設無參數時刪除右端的空白, 有參數時則刪除右端匹配的字元集.

最後是 strip(), 此乃 lstrip() 與 rstrip() 的 OR 情況, 故正規表達式用 ()|() 這種格式即可, 所舉之例為 :

>>> '   spacious   '.strip()
'spacious'
>>> 'www.example.com'.strip('cmowz.')
'example'

範例如下 :

public class mytest {
  public static void main(String[] args) {
    String str="   spacious   ";
    System.out.println(strip(str));                //輸出 "spacious"
    str="www.example.com";           
    System.out.println(strip(str,"cmowz."));  //輸出 "example"
    }
  public static String strip(String str) {
    return str.replaceAll("^\\s+|\\s+$","");
    }
  public static String strip(String str, String chars) {
    return str.replaceAll("(^[" + chars + "]+)|([" + chars + "]+$)","");
    }
  }

# https://docs.python.org/2/library/stdtypes.html
#
Python & Java: A Side-by-Side Comparison

八. 字串比對 :

String 類別有一個 matches() 方法可以用來比對一個字串是否匹配所傳入之正規式, 其 API 為 :



boolean matches(String regex)

此方法會傳回布林值, 範例如下 : 

public class mytest {
  public static void main(String[] args) {
    String str="asabulu@gmail.com";
    String reg="[a-zA-Z0-9_]{6,12}@[a-zA-Z0-9]+(\\.[a-zA-Z]+){1,3}";
    System.out.println(str.matches(reg));  //輸出 true
    str="http://www.google.com.tw";
    System.out.println(str.matches(reg));  //輸出 false
    }
  }


matches() 方法可以應用在將 Python 的字串處理方法改寫到 Java 版上. 例如下列三個 Python 的檢查方法 :
  1. isdigit() : 判別字串內容是否全為數字  (0~9)
  2. isalpha(); 判別字串內容是否全為英文字母
  3. isalnum() : 判別字串內容是否全為數字或英文字母
先來實作 isdigit(), 其正規式很簡單, 用 "\\d+" 或 "[0-9]+" 均可 (用 + 意味必須至少有一個字元, 空字串將回傳 false), 範例如下 :

public class mytest {
  public static void main(String[] args) {
    System.out.println(isdigit("01234"));  //輸出 true
    System.out.println(isdigit("0.1234")); //輸出 false
    System.out.println(isdigit("-123"));    //輸出 false
    System.out.println(isdigit("2a6c"));   //輸出 false
    }
  public static boolean isdigit(String str) {
    return str.matches("\\d+");
    }
  }

其次實作 isalpha(), 其正規式可用 "[a-zA-Z]", 範例如下 :

public class mytest {
  public static void main(String[] args) {
    System.out.println(isalpha("01234"));  //輸出 false
    System.out.println(isalpha("ABCD"));  //輸出 true
    System.out.println(isalpha("abcd"));    //輸出 true
    System.out.println(isalpha("2a6c"));    //輸出 false
    System.out.println(isalpha(""));           //輸出 false
    }
  public static boolean isalpha(String str) {
    return str.matches("[a-zA-Z]+");
    }
  }

接著實作 isalnum(), 其正規式可用 "[0-9a-zA-Z]+" 或 "\\w", 範例如下 :

public class mytest {
  public static void main(String[] args) {
    System.out.println(isalnum("01234"));   //輸出 true
    System.out.println(isalnum("ABCD"));   //輸出 true
    System.out.println(isalnum("abcd"));     //輸出 true
    System.out.println(isalnum("2a6c"));     //輸出 true
    System.out.println(isalnum(""));            //輸出 false
    System.out.println(isalnum("?123+"));   //輸出 false
    }
  public static boolean isalnum(String str) {
    return str.matches("[0-9a-zA-Z]+");
    }
  }

再來實作 ishex(), 此方法用來檢查是否全為 16 進制, 正規式可用 "[0-9a-fA-F]", 範例如下 :

public class mytest {
  public static void main(String[] args) {
    System.out.println(ishex("01234"));     //輸出 true
    System.out.println(ishex("ABCDEF")); //輸出 true
    System.out.println(ishex("abcd"));       //輸出 true
    System.out.println(ishex("2a6c"));       //輸出 true
    System.out.println(ishex(""));              //輸出 false
    System.out.println(ishex("Z123"));       //輸出 false
    }
  public static boolean ishex(String str) {
    return str.matches("[0-9a-fA-F]+");
    }
  }

還有一個是來自 PHP 的 is_numeric(), 可以檢測是否為數值, 包含正負號, 小數點, 以及科學表示法的 e/E, 範例如下 :

public class mytest {
  public static void main(String[] args) {
    System.out.println(isnumeric("1234.56"));    //輸出 true
    System.out.println(isnumeric("-1234.56"));   //輸出 true
    System.out.println(isnumeric("f13c"));         //輸出 false
    System.out.println(isnumeric("1.234E2"));    //輸出 true
    System.out.println(isnumeric("-1.234e-2"));  //輸出 true
    }
  public static boolean isnumeric(String str) {
    String reg="((-|\\+)?[0-9]+(\\.[0-9]+)?)+([eE]?(-|\\+)?[0-9]+)?";
    return str.matches(reg);
    }
  }

 此例中的正規式是用來匹配 email 格式的, 因此當字串是網址時便無法匹配成功.

 參考 :

  1. http://docs.oracle.com/javase/7/docs/api/ (首頁)
  2. http://docs.oracle.com/javase/7/docs/api/java/lang/String.html
  3. http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuffer.html
  4. http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html
  5. http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Array.html
  6. Is Java RegEx case-insensitive?
  7. Regular Expression 在 replace 的應用
  8. 寫入文字檔(可自行指定寫入格式)
  9. Java Gossip: 不可變的(immutable)字串
  10. Java字串的比較
  11. Some simple utility methods I use a lot in Java
  12. Java: function for arrays like PHP's join()?
  13. Some simple utility methods I use a lot in Java
  14. http://commons.apache.org/
  15. http://www.its.washington.edu/bbone/doc/its/util/StringUtils.html
  16. http://docs.oracle.com/javase/tutorial/essential/regex/quant.html 
  17. Converting String to “Character” array in Java  
  18. JAVA 正則表示式 
  19. String.matches()的用法
  20. 正規表示式 Regular Expression
  21. Most elegant isNumeric() solution for java

2 則留言:

  1. 雖然我現在已拋棄 Java 改用 Python 與 R, 但我不會覺得 Java 是垃圾, 它曾是眾多高手的結晶, 如果說我寫的這篇是垃圾, 我可以接受, 因為那只是我個人的筆記, 那也許是垃圾, 但心中汙穢的人, 看啥都是垃圾.

    回覆刪除