文章目錄
正規表達式是一個強大的字元串處理工具 ,可以對字元串進行查找、提取、分割、替換等操作 。 String類裡也提供了如下幾個特殊的方法 :
- boolean matches(String regex): 判斷該宇符串是否比對指定的正規表達式 。
- String replaceAll(String regex, String replacement): 将該宇符串中所有比對regex 的子串替換成replacement 。
- String replaceFirst(String regex, String replacement): 将該字元串中第一個比對 regex 的子串替換成 replacement 。
- String[] split(String regex): 以 regex 作為分隔符,把該字元串分割成多個子串 。
上面這些特殊的方法都依賴于 Java 提供的正規表達式支援,除此之外, Java 還提供了 Pattem 和Matcher 兩個類專門用于提供正規表達式支援。
正規表達式就是一個用于比對字元串的模闆,可以比對一批字元串,是以建立正規表達式就是建立一個特殊的字元串 。
在其他語言中,\\ 表示:想要在正規表達式中插入一個普通的(字面上的)反斜杠,不要給它任何特殊的意義。在 Java 中,\\ 表示:要插入一個正規表達式的反斜線,是以其後的字元具有特殊的意義。
是以,在其他的語言中(如Perl),一個反斜杠 \ 就足以具有轉義的作用,而在 Java 中正規表達式中則需要有兩個反斜杠才能被解析為其他語言中的轉義作用。也可以簡單的了解在 Java 的正規表達式中,兩個 \ 代表其他語言中的一個 \,這也就是為什麼表示一位數字的正規表達式是 \d,而表示一個普通的反斜杠是 \\。
正規表達式所支援的合法字元如表一所示 :
表一:正規表達式所支援的合法字元
正規表達式中有一些特殊字元,這些特殊字元在正規表達式中有其特殊的用途:
表二:正規表達式中的特殊字元
将上面多個字元拼起來 , 就可以建立一個正規表達式。例如:
" \u0041\\\\ " // 比對 A \
" \u0061 \t " // 比對 a <制表符〉
" \\?\\ [" // 比對? [
上面的正規表達式依然隻 能比對單個字元,這是因為還未在正規表達式中使用"通配符","通配符"是可以比對多個字元的特殊字元。正規表達式中 的"通配符"遠遠超出了普通通配符的功能,它被稱為預定義字元:
表三:預定義字元
上面的 7 個預定義字元其 實很容易記憶: d 是 digit 的意思,代表數字; s 是 space的意思, 代表空白; W 是 word 的意思 , 代表單詞 。 d 、 s 、 w 的大寫形式恰好比對與之相反的字元 。
有了上面的預定義字元後 ,接下來就可以建立更強大的正規表達式了。 例如:
c\\wt //可 以比對 cat 、 cbt 、 cct 、 cOt 、 c9t 等一批字元串
\\d\\d\\d-\\d\\d\\d-\d\\d\\d\\d //比對如 000-000-0000 形式的電話号碼
隻想比對 a~ f 的字母 ,或者比對除 ab 之外的所有小寫字母,或者比對中文字元,此時就需要使用方括号表達式:
表四:方括号表達式
正則表示還支援圓括号表達式,用于将多個表達式組成一個子表達式 ,圓括号中可 以使用或運算符(|)。 例如, 正 則 表達式 "((public)|(Protected)l(private))"用于比對 Java 的 三個通路控制符其中之 一。
Java 正規表達式還支援邊界比對符 :
表五:邊界比對符
前面例子中需要建立一個比對 000-000-0000 形式的電話号碼時,使用了\\d\d\d-\d\d\d-\d\d\d\d
正規表達式,這看起來比較煩瑣 。 實際上,正規表達式還提供了數量辨別符,正規表達式支援的數量辨別符有如下幾種模式 :
- Greedy (貪婪模式) : 數量表示符預設采用貪婪模式 , 除非另有表示。貪婪模式的表達式會一直比對下去 ,直到無法比對為止 。 如果你發現表達式比對的結果與預期的不符 , 很有可能是因為一一你以為表達式隻會比對前面幾個宇符,而實際上它是貪婪模式 , 是以會一直比對下去 。
- Reluctant (勉強模式) : 用問号字尾(?) 表示 , 它隻會匹自己最少的字元 。 也稱為最小比對模式 。
- Possessive (占有模式) : 用加号字尾(+)表示 ,目前隻有 Java 支援占有模式,通常比較少用 。
三種模式的數量表示符如表六所示 。
表六:三種模式的數量表示符
一旦在程式中定義了正規表達式,就可以使用 Pattem 和 Matcher 來使用正規表達式 。
Pattem 對象是正規表達式編譯後在記憶體中的表示形式,是以,正規表達式宇符串必須先被編譯為Pattem 對象,然後再利用該 Pattem 對象建立對應的 Matcher 對象 。 執行比對所涉及的狀态保留在 Matcher對象中,多個 Matcher 對象可共享同一個 Pattem 對象 。
是以,典型的調用順序如下:
/ /将一個字元串編譯成 Pattern 對象
Pattern p = Pattern.compil e( "a*b");
// 使用 Pattern 對象建立 Matcher 對象
Matcher m = p .matcher( "aaaaab" ) ;
boolean b = m.matches(); / /傳回 true
上面定義的 Pattem 對象可以多次重複使用 。 如果某個正規表達式僅需一次使用,則可直接使用Pattem 類的靜态 matches()方法,此方法自動把指定字元串編譯成匿名的 Pattem 對象,并執行比對,如下所示 :
boolean b = Pattern.matches("a*b" , "aaaaab"); // 傳回 true
Pattem 是不可變類,可供多個并發線程安全使用 。
Matcher 類提供了如下幾個常用方法 :
- find(): 傳回目标字元串中是否包含與 Pattem 比對的子 串 。
- group(): 傳回上一次與 Pattem 比對的子串 。
- start(): 傳回上一 次與 Pattem 比對的子串在目标字元串中的開始位置 。
- end(): 傳回上一次與 Pattem 比對的子串在目标字元串中的結束位置加 1 。
- lookingAt() : 傳回目标字元串前面部分與 Pattem 是否比對 。
- matches() : 傳回整個目标字元串與 Pattem 是否比對 。
- reset(): 将現有的 Matcher 對象應用于一個新的字元序列 。
通過 Matcher 類的 findO和 groupO方法可以從目标字元串中依次取出特定子串(比對正規表達式的子串),例如網際網路的網絡爬蟲,它們可以自動從網頁中識别出所有的電話号碼 。 下面程式示範了如何從大段的宇符串中找出電話号碼 :
FindGroup.java
public class FindGroup
{
public static void main(String[] args)
{
// 使用字元串模拟從網絡上得到的網頁源碼
String str = "我想求購一本《***》,盡快聯系我13500006666"
+ "交朋友,電話号碼是13611125565"
+ "出售二手電腦,聯系方式15899903312";
// 建立一個Pattern對象,并用它建立一個Matcher對象
// 該正規表達式隻抓取13X和15X段的手機号,
// 實際要抓取哪些電話号碼,隻要修改正規表達式即可。
Matcher m = Pattern.compile("((13\\d)|(15\\d))\\d{8}")
.matcher(str);
// 将所有符合正規表達式的子串(電話号碼)全部輸出
while(m.find())
{
System.out.println(m.group());
}
}
}
運作結果:
find()方法依次查找字元串中與 Pattem 比對的子串, 一旦找到對應的子
串,下次調用 find()方法時将接着向下查找。
find()方法還可以傳入一個 int 類型的參數,帶 int 參數的 find()方法将從該 int 索引處向下搜尋 。start()和 end()方法主要用于确定子串在目标字元串中的位置,如下程式所示:
StartEnd.java
public class StartEnd
{
public static void main(String[] args)
{
// 建立一個Pattern對象,并用它建立一個Matcher對象
String regStr = "Java is very easy!";
System.out.println("目标字元串是:" + regStr);
Matcher m = Pattern.compile("\\w+")
.matcher(regStr);
while(m.find())
{
System.out.println(m.group() + "子串的起始位置:"
+ m.start() + ",其結束位置:" + m.end());
}
}
}
matchesO和 lookingAt()方法有點相 似,隻 是 matches()方法要求整個字元串和 Pattem 完全比對時才傳回 true ,而 lookingAtO隻要字元串以 Pattem 開頭就會傳回 true 。 reset()方法可将現有的 Matcher 對象應用于新的字元序列 。看如下程式:
MatchesTest.java
public class MatchesTest
{
public static void main(String[] args)
{
String[] mails =
{
"[email protected]" ,
"[email protected]",
"[email protected]",
"[email protected]"
};
String mailRegEx = "\\w{3,20}@\\w+\\.(com|org|cn|net|gov)";
Pattern mailPattern = Pattern.compile(mailRegEx);
Matcher matcher = null;
for (String mail : mails)
{
if (matcher == null)
{
matcher = mailPattern.matcher(mail);
}
else
{
matcher.reset(mail);
}
String result = mail + (matcher.matches() ? "是" : "不是")
+ "一個有效的郵件位址!";
System.out.println(result);
}
}
}
除此之外 ,還可以利用正規表達式對目标字元串進行分割、查找、替換等操作,看如下程式:
ReplaceTest.java
public class ReplaceTest
{
public static void main(String[] args)
{
String[] msgs =
{
"Java has regular expressions in 1.4",
"regular expressions now expressing in Java",
"Java represses oracular expressions"
};
Pattern p = Pattern.compile("re\\w*");
Matcher matcher = null;
for (int i = 0 ; i < msgs.length ; i++)
{
if (matcher == null)
{
matcher = p.matcher(msgs[i]);
}
else
{
matcher.reset(msgs[i]);
}
System.out.println(matcher.replaceAll("哈哈:)"));
}
}
}
API: java.util.regex.Matcher java.util.regex.Pattern
參考:
【1】:《瘋狂Java講義》
【2】:
Java正規表達式【3】:
正規表達式比對規則 正規表達式複雜比對規則【4】:
正規表達式教程