字符串對象
使用正則表達式最簡單的辦法,就是直接調用字符串對象的方法。
- matches : 檢查是否匹配上指定的正則表達式
System.out.println("1234".matches("\\d+")); // true
- split : 將字符串從指定的正則表達式匹配的位置拆分,另外還有一個重載的方法可以指定拆分成多少個
String str = "Hello world 47"; String[] arr = str.split(" "); System.out.println(Arrays.toString(arr)); // [Hello, world, 47] arr = str.split(" ", 2); System.out.println(Arrays.toString(arr)); // [Hello, world 47]
-
replaceFirst、replaceAll : 替換第一個、全部匹配上指定正則表達式的子串
String str = "Hello world 47"; System.out.println(str.replaceFirst("\\d", "*")); // Hello world *7 System.out.println(str.replaceAll("\\d", "*")); // Hello world **
Pattern和Matcher對象的創建
由於String類的功能有限,所以我們經常需要構建功能強大的正則表達式對象。通過Pattern.compile()方法來根據傳入的String類型的正則表達式生成Pattern對象,然后把需要檢索的字符串傳入Pattern類的matcher方法生成Matcher對象,Matcher中提供了大量的方法滿足我們的需求。Matcher對象的創建過程如下
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher("123456");
其中Pattern還提供了一個重載的compile方法,第二個參數為標記參數(可以傳入多個用"|"連接),這些標記都是Pattern類中的常量。如下
- Pattern.CANON_EQ:當且僅當兩個字符的完全規范分解都相同的情況下,才認定匹配。比如用了這個標志之后,表達式"a/u030A"會匹配"\u00E5"(默認不匹配)
- Pattern.CASE_INSENSITIVE(?i)、Pattern.UNICODEC_CASE(?u):兩個結合使用可以無視大小寫(默認只有US-ASUII字符集是可以)
- Pattern.COMMENTS(?x):空格與#開頭的行到行末會被忽略
- Pattern.DOTALL(?s):"."可以匹配所有字符包括換行符(默認不包括)
- Pattern.MULTILNE(?m):多行情況下"^"和"$"分別匹配一行的開始與結尾(默認是整個字符串的開始與結尾)
- Pattern.UNIX_LINES(?d):"."、"^"和"&"只識別換行符"\n"
以上標記參數后面的括號內的字符若直接插入在正則表達中,將擁有與傳入標記參數一樣的效果。如下所示
Pattern p = Pattern.compile("^java", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); //Pattern p = Pattern.compile("(?i)(?m)^java"); Matcher m = p.matcher("java is good\nJAVA is best"); while (m.find()) System.out.print(m.group() + " "); // java JAVA
上面代碼中用到Matcher對象的find與group方法將在下面進行講解。可以看出以上兩種創建Pattern對象的方式,將不會影響最后的輸出結果。而且由於傳入了標記參數所以可以無視大小寫成功匹配JAVA並且字符串中含有換行符所以匹配到了兩個結果
Matcher對象的方法以及使用
- matches:判斷整個字符串是否都匹配正則表達式
- lookingAt:從字符串的開頭判斷是否匹配正則表達式但可以不用整個都匹配
- find:像迭代器那樣向前遍歷字符串,查找是否有匹配字符串片段。該方法還有一個重載的方法,可以傳入一個索引值,即從該索引位置起查找是否有匹配的
- group:當沒有參數時返回前一次匹配成功的字符串(匹配整個正則表達式),由於一個正則表達式可以有包含多個括號,即擁有多個組,所以該方法可以傳入一個數字,來返回匹配上某個組的字符串,當傳入的數字為0時與未傳參一樣
- groupCount:返回該正則表達式總共有可以分成多少組
String s = "Hello world, my name is ghaien.\n" + "this is a demo from a book.\n" + "it's named thinking in java."; Matcher m = Pattern.compile("(?m)((\\S+)\\s+(\\S+))$").matcher(s); while (m.find()) { for (int i = 0; i < m.groupCount(); i++) System.out.print("[" + m.group(i) + "]"); System.out.println(); }/* output [is ghaien.][is ghaien.][is] [a book.][a book.][a] [in java.][in java.][in] */
- start:返回先前匹配上的字符串的起始位置的索引值
- end:返回先前匹配上的字符串的最后位置的索引值加一
- replaceFirst、replaceAll:將匹配上的字符串的第一個、所有替換成指定的字符串
- appendReplacement:這個方法會對字符串進行漸進式的替換,並將替換后的字符串通過指定的StringBuffer對象拼接起來
- appendTail:通常用來結合上一個方法來使用,當替換了多次之后可以調用這個方法將后面沒有被替換的字符串復制到StringBuffer中
String s = "Hello world 47"; Matcher m = Pattern.compile("[a-zA-Z]").matcher(s); System.out.println(m.replaceFirst("*")); m = Pattern.compile("[a-zA-Z]").matcher(s); System.out.println(m.replaceAll("*")); m = Pattern.compile("[a-zA-Z]").matcher(s); StringBuffer sb = new StringBuffer(); int i = 0; while (m.find()) m.appendReplacement(sb, i++ + ""); System.out.println(sb); m.appendTail(sb); System.out.println(sb); /* output *ello world 47 ***** ***** 47 01234 56789 01234 56789 47 */
從上面的代碼中可以看出replaceFirst與replaceAll只能將一個或所有匹配的替換成某個指定的字符串,這有時候並不能滿足我們的需求,而appendReplacement方法的替換是漸進式的並且每次都能替換成我們所需要的,從后面來兩個輸出的結果也能夠很直接的看出appendTail方法的作用
- reset:可以將現有的Matcher對象應用於一個新的字符串