java語言中的正則表達式匹配功能
java語言中的正則表達式匹配功能主要是通過java.util.regex.Matcher類和以下這些方法實現的。
- find():在一個字符串里尋找一個給定模式的匹配。
- lookingAt(): 用一個給定的模式去嘗試匹配一個字符串的開頭。
- matches():用一個給定的模式去嘗試匹配一個完整的字符串。
- replaceAll():進行替換操作,對所有的匹配都進行替換。
- replaceFirst():進行替換操作,只對第一個匹配進行替換。
matcher類還提供了幾個能夠讓程序員對特定操作做出更細致調控的方法。此外,java.util.regex.pattern類也提供了幾個簡單易用的包裝器方法。 - compile():把一個正則表達式編譯成一個模式。
- flags():返回某給定模式的匹配標志。
- matches():在功能上等價於剛才介紹的matches()方法。Pattern類的構造方法是私有的,所以我們使用
Pattern p = Pattern.compile("a*b")
進行實例化;Matcher類的實例化依賴Pattern類的對象Matcher m = p.matcher("aaaaab")
; - pattern():把一個模式還原為一個正則表達式。
- split():把一個字符串分為子字符串。
在實際的開發中,為了方便我們很少直接使用Pattern類或Matcher類,而是使用String類下的方法
- 驗證:
boolean matches(String regex)
- 拆分:
String[] split(String regex)
- 替換:
String replaceAll(String regex, String replacement)
注意事項
Sun公司發布的Java正則表達式支持與Perl語言基本兼容,但要注意以下幾點。
- 要想使用正則表達式,必須先用
import java.util.regex.*
語句導入正則表達式組件(這條語句將導入一個完整的軟件包。如果你只需要用到其中的一部分功能,請用相應的軟件包名字替換掉這條語句里的*)。 - 不支持嵌入條件。
- 不支持使用\E、\l、\L、\u和\U進行字母大小寫轉換。
- 不支持使用\b匹配退格符。
- 不支持\z。
java中正則表達式常用的語法
字符的取值范圍
- [abc] : 表示可能是a,可能是b,也可能是c。
- [^abc]: 表示不是a,b,c中的任意一個
- [a-zA-Z]: 表示是英文字母
- [0-9]:表示是數字
簡潔的字符表示
- .:匹配任意的字符
- \d:表示數字
- \D:表示非數字
- \s:表示由空格組成,[ \t\n\r\x\f]
- \S:表示由非空字符組成,[^\s]
- \w:表示字母、數字、下划線,[a-zA-Z0-9_]
- \W:表示不是由字母、數字、下划線組成
- \b:匹配一個字邊界,即字與空格間的位置。例如,"er\b"匹配"never"中的"er",但不匹配"verb"中的"er"。
- \B:非字邊界匹配。"er\B"匹配"verb"中的"er",但不匹配"never"中的"er"。
數量表達式
- ?: 表示出現0次或1次
- +: 表示出現1次或多次
- *: 表示出現0次、1次或多次
- {n}:表示出現n次
- {n,m}:表示出現n~m次
- {n,}:表示出現n次或n次以上
- ?:當此字符緊隨任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后時,匹配模式是"非貪心的"。"非貪心的"模式匹配搜索到的、盡可能短的字符串,而默認的"貪心的"模式匹配搜索到的、盡可能長的字符串。例如,在字符串"oooo"中,"o+?"只匹配單個"o",而"o+"匹配所有"o"。
注意:*, +, {n,}都是常用的貪婪型元字符,在匹配時它們會盡可能地從一段文本的開頭一直匹配到這段文本的末尾,而不是從這段文本的開頭匹配到碰到第一個匹配時為止。
例如:
文本:
living in <B>AK</B> and <B>HI</B>.
正則表達式:
<Bb>.*<Bb>
結果:
living in <B>AK</B> and <B>HI</B>.
這時需要使用相應的懶惰型元字符,防止過度匹配,在貪婪型元字符后加上一個?后綴即可,即*?、+?、{n,}?等。
例如:
文本:
living in <B>AK</B> and <B>HI</B>.
正則表達式:
<Bb>.*?<Bb>
結果:
living in <B>AK</B> and <B>HI</B>.
邏輯表達式
- XY: 表示X后面跟着Y,這里X和Y分別是正則表達式的一部分
- X|Y:表示X或Y,比如"food|f"匹配的是foo(d或f),而"(food)|f"匹配的是food或f
- (X):子表達式,將X看做是一個整體
多用途元字符
- *:只有當它出現在一個字符集合里(被放在[和]之間)並緊跟在左方括號[的后面時,它才能發揮“求非”作用。如果是在一個字符集合的外面並位於一個模式的開頭,^將匹配字符串的開頭。
例如:[^abc]: 表示不是a,b,c中的任意一個;
^\s*<\?xml.*\?>:匹配一個<?xml>標簽內容,並且該內容出現在字符串的開頭
相應的,$匹配字符串的結尾,如\s*$匹配一個字符串結尾處的零個或多個空白字符
回溯引用匹配:前后一致匹配
例如:
文本:
<H1>ColdFusion</H1>
<H2>ColdFusion</H2>
<H2>This is not valid HTML</H3>
正則表達式:
<[hH][1-6]>.*?</[hH][1-6]>
結果:
<H1>ColdFusion</H1>
<H2>ColdFusion</H2>
<H2>This is not valid HTML</H3>
分析:
在這個例子里,原始文本里有一個標題是以<H2>開頭、以<H3>結束的。這顯然是一個不合法的標題,但它與我們所使用的模式匹配上了。出現這種情況的根源是這個模式的第2部分(用來匹配結束標簽的那個部分)對這個模式的第1部分(用來匹配開始標簽的那個部分)毫無所知。要想徹底解決這個問題,就只能求助於回溯引用。
再如:
文本:
This is a block of of text, several words here are are repeated
正則表達式:
[ ]+(\w+)[ ]+\1
結果:
This is a block of of text, several words here are are repeated
分析:
[ ]+匹配一個或多個空格,\w+匹配一個或多個字母數字字符,[ ]+匹配隨后的空格。注意,\w+是括在括號里的,它是一個子表達式。這個子表達式不是用來進行重復匹配的,這里根本不涉及重復匹配的問題。這個子表達式只是把整個模式的一部分單獨划分出來以便在后面引用。這個模式的最后一部分是\1;這是一個回溯引用,而它引用的正是前面划分出來的那個子表達式:當(\w+)匹配到單詞of的時候,\1也匹配單詞of;當(\w+)匹配到單詞and的時候,\1也匹配單詞and。可以把回溯引用想像成變量
所以,上一個例子的正則表達應該寫成:
<[hH]([1-6])>.*?</[hH]\1>
結果:
<H1>ColdFusion</H1>
<H2>ColdFusion</H2>
<H2>This is not valid HTML</H3>
分析:
<[hH]([1-6])>匹配任何一級標題的開始標簽,但我們這次用(和)把[1-6]括了起來,使它成為了一個子表達式。這樣一來,我們就可以在用來匹配標題結束標簽的</[hH]\1>用\1來引用這個子表達式了。子表達式([1-6])匹配數字1~6, \1只匹配與之相同的數字。這樣一來,原始文本里的<H2>This is notvalid HTML就不會被匹配到了。
回溯引用在替換操作中的應用
如下例:
文本:
Hello, ben@forta.com is my email address!
正則表達式:
\w+[\w.]*@[\w.]+\.\w+
結果:
Hello, ben@forta.com is my email address!
分析:
這個模式可以把原始文本里的電子郵件地址查找出來。現在,假設你需要把原始文本里的電子郵件地址全都轉換為可點擊的鏈接,你該怎么辦?在HTML文檔里,你需要使用
<A HREF="maito:user@address.com">user@address.com</A>這樣的語法來創建一個可點擊的電子郵件地址。能不能用一個正則表達式把一個電子郵件地址轉換為這種可點擊的地址格式呢?當然能,而且非常容易——但前提是你得使用回溯引用,如下所示:
文本:
Hello, ben@forta.com is my email address!
正則表達式:
(\w+[\w.]*@[\w.]+\.\w+)
替換:
<A HREF="mailto:$1">$1</A>
Java代碼:
public static void main(String[] args) {
// 1. 回溯引用在替換操作中的應用
String str = "Hello, ben@forta.com is my email address!";
String regex = "(\w+[\w.]*@[\w.]+\.\w+)";
Pattern pat = Pattern.compile(regex); //實例化Pattern對象
Matcher mat = pat.matcher(str); //實例化Matcher對象
while(mat.find()) {
System.out.println(mat.replaceAll("<A HREF=\"mailto:$1\">$1</A>"));
}
}
結果:
轉義字符
在其他語言中,\\
表示:我想要在正則表達式中插入一個普通的(字面上的)反斜杠,請不要給它任何特殊的意義。
在 Java 中,\\
表示:我要插入一個正則表達式的反斜線,所以其后的字符具有特殊的意義。
所以,在其他的語言中(如 Perl),一個反斜杠 \
就足以具有轉義的作用,而在 Java 中正則表達式中則需要有兩個反斜杠才能被解析為其他語言中的轉義作用。也可以簡單的理解在 Java 的正則表達式中,兩個 \\
代表其他語言中的一個 \
,這也就是為什么表示一位數字的正則表達式是 \\d
,而表示一個普通的反斜杠是 \\
。
System.out.print("\\"); // 輸出為 \
System.out.print("\\\\"); // 輸出為 \\
了解更多請轉到 RUNOOB.COM