1、句點符號
假設在玩英文拼字遊戲,想要找出三個字母的單詞,而且這些單詞必須以“t”字母開頭,以“n”字母結束。要構造出這個Regex,可以使用一個萬用字元——句點符號“.”。這樣,完整的運算式就是“t.n”,它匹配“tan”、“ten”、“tin”和“ton”,還匹配“t#n”、“tpn”甚至“t n”,還有其他許多無意義的組合。這是因為句點符號匹配所有字元,包括空格、Tab字元甚至分行符號。
2、方括弧符號
為瞭解決句點符號匹配範圍過於廣泛這一問題,你可以在方括弧(“[]”)裡面指定看來有意義的字元。此時,只有方括弧裡面指定的字元才參與匹配。也就是說,Regex“t[aeio]n”只匹配“tan”、“Ten”、“tin”和“ton”。但“Toon”不匹配,因為在方括弧之內只能匹配單個字元。
此外,方括弧內還可以用“-”表示跨度,如“[a-g]”匹配字母表中a到g的小寫字母,“[1-9]”匹配1到9的數字。
可以使用“&&”取交集,比如“[1-9&&[^456]]”,匹配1到9中除了4、5、6以外的數字。
3、“或”符號
如果除了上面匹配的所有單詞之外,還想要匹配“toon”,那麼,你可以使用“|”操作符。“|”操作符的基本意義就是“或”運算。要匹配“toon”,使用“t(a|e|i|o|oo)n”Regex。這裡不能使用方擴號,因為方括弧只允許匹配單個字元;這裡必須使用圓括弧“()”。圓括弧還可以用來分組。
4、表示匹配次數的符號
? 0次或1次
+ 1次或多次,即至少1次
* 0次或多次,即任意多次
{n} 恰好n次
{n,m} n次到m次
假設我們要在文字檔中搜尋美國的社會安全號碼。這個號碼的格式是999-99-9999。用來匹配它的Regex如所示。在Regex中,連字號(“-”)有著特殊的意義,它表示一個範圍,比如從0到9。因此,匹配社會安全號碼中的連字號號時,它的前面要加上一個逸出字元“\”。
假設進行搜尋的時候希望連字號號可以出現,也可以不出現——即,999-99-9999和999999999都屬於正確的格式。這時,可以在連字號號後面加上“?”數量限定符號,如所示:
5、“否”符號
“^”符號稱為“否”符號。如果用在方括弧內,“^”表示不想要匹配的字元。例如,的Regex匹配所有單詞,但以“X”字母開頭的單詞除外。
6、圓括弧
(1)限定量詞作用的範圍
例
(cat)? 匹配0個或1個“cat”
(cat)+ 匹配1個或多個“cat”
(2)限定多選結構的範圍
例
(cat|dog) 匹配“cat”或“dog”
(3)分組捕獲
位於圓括弧之間的模式比對的內容都會被捕獲,當模式中有嵌套的圓括弧時,變數的編號會按照圓開括弧出現的位置一次進行。
例
([A-Za-z](\d{2}))((-)\d{2})匹配”A22-33”時,匹配情況如下:
第一個出現的圓括弧中的Regex為:[A-Za-z](\d{2})
匹配結果Group 1: A22
第二個出現的圓括弧中的Regex為:\d{2}
匹配結果Group 2: 22
第三個出現的圓括弧中的Regex為:(-)\d{2}
匹配結果Group 3: -33
第四個出現的圓括弧中的Regex為:-
匹配結果Group 4: -
(4)分組不捕獲
當圓括弧與“?:”組合使用時,表示非捕獲型分組。圓括弧的內容不作為捕獲對象,當圓括弧中的內容不是想捕獲的對象時,採用非捕獲圓括弧可以提高匹配效率。
例
(\w(?:\d{2}))((?:-)\d{2})匹配” A22-33”情況如下:
Group 1: A22
Group 2: -33
註:\d{2}匹配的”22”沒有被捕獲,-匹配的“-”也沒有被捕獲。
(5)反向引用捕獲文本
例
([ab])\1,圓括弧內的“[ab]” 可以匹配“a”或“b”,後面的“\1”代表,如果前面匹配的文本引用。如果擷取的群組匹配到“a”,那麼反向引用也就只能匹配“a”,同理,如果擷取的群組匹配到的是“b”,那麼反向引用也就只能匹配“b”。由於後面反向引用“\1”的限制,要求必須是兩個相同的字元,在這裡也就是“aa”或者“bb”才能匹配成功。
(6)前瞻
當圓括弧與“?=”組合使用時,表示前瞻,代表該運算式會作為匹配校正,但不會出現在匹配結果字串裡面。
例
(John) (?=Resig)匹配情況如下:
John:不匹配,因為後面沒有跟著Resig
John Backus:不匹配,後面跟著的不是Resig
John Reisg:匹配,John後面跟著Resig。但是匹配的結果是“John”而不是“JohnReisg”。
7、預定義字元
\d 數字字元:[0-9]
\D 非數字字元:[^0-9]
\s 空白字元:[\t\n\x0B\f\r]
\S 非空白字元:[^\s]
\w 單詞字元:[a-zA-Z_0-9]
\W 非單詞字元:[^\w]
8、邊界匹配字元
^ 行首
$ 行尾
\b 單詞邊界
\B 非單詞邊界
\A 輸入的開頭
\G 上一個匹配的結尾
\Z 輸入的結尾,僅用於最後的結束符(如果有的話)
\z 輸入的結尾
9、匹配模式
Regex有三種匹配模式:貪婪(greedy)、勉強(reluctant)和侵佔(possessive)
貪婪 勉強 侵佔
X? X?? X?+ 匹配 X 零次或一次
X* X*? X*+ 匹配 X 零次或多次
X+ X+? X++ 匹配 X 一次或多次
X{n} X{n}? X{n}+ 匹配 X n 次
X{n,} X{n,}? X{n,}+ 匹配 X 至少 n 次
X{n,m} X{n,m}? X{n,m}+ 匹配 X 至少 n 次,但不多於 m 次
例
假定要分析的字串是:xfooxxxxxxfoo
模式:.*foo (貪婪模式):
模式分為子模式p1(.*)和子模式p2(foo)兩個部分. 其中p1中的量詞匹配方式使用預設(貪婪型)。匹配開始時,吃入所有字元xfooxxxxxxfoo去匹配子模式p1。匹配成功,但這樣以來就沒有了字串去匹配子模式p2。本輪匹配失敗;第二輪:減少p1部分的匹配量,吐出最後一個字元, 把字串分割成xfooxxxxxxfo和o兩個子字串s1和s2。 s1匹配p1, 但s2不匹配p2。本輪匹配失敗;第三輪,再次減少p1部分匹配量,吐出兩個字元,字串被分割成xfooxxxxxxfo和oo兩部分。結果同上。第四輪,再次減少p1匹配量, 字串分割成xfooxxxxxx和foo兩個部分,,這次s1/s2分別和p1/p2匹配。停止嘗試,返回匹配成功。
模式:.*?foo (勉強模式): 最小匹配方式。第一次嘗試匹配, p1由於是0或任意次,因此被忽略,用字串去匹配p2,失敗;第二次,讀入第一個字元x,嘗試和p1匹配,,匹配成功;字串剩餘部分fooxxxxxxfoo中前三個字元和p2也是匹配的。因此,停止嘗試,返回匹配成功。在這種模式下,如果對剩餘字串繼續去尋找和模式相匹配的子字串,還會找到字串末尾的另一個xfoo,而在貪婪模式下,由於第一次匹配成功的子串就已經是所有字元,因此不存在第二個匹配子串。
模式:.*+foo (侵佔模式): 也叫佔用模式。匹配開始時讀入所有字串,和p1匹配成功, 但沒有剩餘字串去和p2匹配。因此,匹配失敗。返回。
簡單地說,貪婪模式和佔有模式相比, 貪婪模式會在只有部分匹配成功的條件下,依次從多到少減少匹配成功部分模式的匹配數量,將字元留給模式其他部分去匹配;而佔用模式則是佔有所有能匹配成功部分,絕不留給其他部分使用。
佔用模式目前只有java支援,通常比較少用。
Java中的RegexAPI
JDK中與Regex相關的類位於java.util.regex包下。有兩個類Pattern和Matcher。
Pattern類
方法摘要:
static Pattern compile(String regex)
將給定的Regex編譯到模式中。
static Pattern compile(String regex, int flags)
將給定的Regex編譯到具有給定標誌的模式中。
Matcher matcher(CharSequenceinput)
建立匹配給定輸入與此模式的匹配器。CharSequence是一個介面,String,StringBuffer,StringBuilder都是其實作類別。
static boolean matches(String regex, CharSequence input)
編譯給定Regex並嘗試將給定輸入與其匹配。
String[] split(CharSequenceinput)
圍繞此模式的匹配拆分給定輸入序列。
String[] split(CharSequenceinput, int limit)
圍繞此模式的匹配拆分給定輸入序列。
Pattern 類定義了備用的compile 方法,用於接受影響模式比對方式的標誌集。標誌參數是一個位元遮罩,可以是下面公用靜態欄位中的任意一個:
Pattern.CANON_EQ
啟用規範等價。在指定此標誌後,若且唯若在其完整的規範分解匹配時,兩個字元被視為匹配。例如,運算式a\u030A[8]在指定此標誌後,將匹配字串“\u00E5”(即字元 å)。預設情況下,匹配不會採用規範等價。指定此標誌可能會對效能會有一定的影響。
Pattern.CASE_INSENSITIVE
啟用不區分大小寫匹配。預設情況下,僅匹配 US-ASCII 字元集中的字元。Unicode 感知(Unicode-aware)的不區分大小寫匹配,可以通過指定 UNICODE_CASE 標誌連同此標誌來啟用。不區分大小寫匹配也能通過內嵌標誌運算式(?i)來啟用。指定此標誌可能會對效能會有一定的影響。
Pattern.COMMENTS
模式中允許存在空白和注釋。在這種模式下,空白和以#開始的直到行尾的內嵌注釋會被忽略。注釋模式也能通過內嵌標誌運算式(?x)來啟用。
Pattern.DOTALL
啟用 dotall 模式。在 dotall 模式下,運算式.匹配包括行結束符在內的任一字元。預設情況下,運算式不會匹配行結束符。dotall 模式也通過內嵌標誌運算式(?x)來啟用。[s 是“單行(single-line)”模式的助記符,與 Perl 中的相同。]
Pattern.LITERAL
啟用模式的字面分析。指定該標誌後,指定模式的輸入字串作為字面上的字元序列來對待。輸入序列中的元字元和逸出字元不具有特殊的意義了。CASE_INSENSITIVE 和 UNICODE_CASE 與此標誌一起使用時,會對匹配產生一定的影響。其他的標誌就變得多餘了。啟用字面分析沒有內嵌標誌運算式。
Pattern.MULTILINE
啟用多行(multiline)模式。在多行模式下,運算式^和$分別匹配輸入序列行結束符前面和行結束符的前面。預設情況下,運算式僅匹配整個輸入序列的開始和結尾。多行模式也能通過內嵌標誌運算式(?m)來啟用。
Pattern.UNICODE_CASE
啟用可摺疊感知 Unicode(Unicode-awarecase folding)大小寫。在指定此標誌後,需要通過 CASE_INSENSITIVE 標誌來啟用,不區分大小寫區配將在 Unicode 標準的意義上來完成。預設情況下,不區分大小寫匹配僅匹配 US-ASCII 字元集中的字元。可摺疊感知 Unicode 大小寫也能通過內嵌標誌運算式(?u)來啟用。指定此標誌可能會對效能會有一定的影響。
Pattern.UNIX_LINES
啟用 Unix 行模式。在這種模式下,.、^和$的行為僅識別“\n”的行結束符。Unix 行模式可以通過內嵌標誌運算式(?d)來啟用。
Matcher類
方法摘要:
int end()
返回最後匹配字元之後的位移量。
int end(intgroup)
返回在以前的匹配操作期間,由給定組所捕獲子序列的最後字元之後的位移量。
boolean find()
嘗試尋找與該模式比對的輸入序列的下一個子序列。
boolean find(intstart)
重設此匹配器,然後嘗試尋找匹配該模式、從指定索引開始的輸入序列的下一個子序列。
String group()
返回由以前匹配操作所匹配的輸入子序列。
String group(intgroup)
返回在以前匹配操作期間由給定組捕獲的輸入子序列。
int groupCount()
返回此匹配器模式中的擷取的群組數。
boolean matches()
嘗試將整個地區與模式比對。
Pattern pattern()
返回由此匹配器解釋的模式。
String replaceAll(Stringreplacement)
替換模式與給定替換字串相匹配的輸入序列的每個子序列。
String replaceFirst(Stringreplacement)
替換模式與給定替換字串匹配的輸入序列的第一個子序列。
Matcher reset()
重設匹配器。
Matcher reset(CharSequenceinput)
重設此具有新輸入序列的匹配器。
int start()
返回以前匹配的初始索引。
int start(intgroup)
返回在以前的匹配操作期間,由給定組所捕獲的子序列的初始索引。
MatchResult toMatchResult()
作為 MatchResult 返回此匹配器的匹配狀態。
Matcher usePattern(PatternnewPattern)
更改此 Matcher 用於尋找匹配項的Pattern。
執行個體
String regex = "((A+)(B(C)))"; String input ="ABC-AABC-AAAAABCD"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(input); int groupCount =matcher.groupCount(); //regex被圓括弧分為四組,按照括弧的出現位置,分別為:((A+)(B(C)))、(A+)、(B(C))、(C) //匹配的時候,還是按照A+BC 去搜尋,只不過,每次匹配成功後,會將搜到的字串按照上面的四組規則分為四個子串,儲存起來 while(matcher.find()){ System.out.print("匹配結果:"); for(inti=0;i<groupCount;i++){ System.out.print("group"+i+":"+matcher.group(i)+"\t"); } System.out.println(); }
輸出:
匹配結果:group0:ABC group1:ABC group2:A group3:BC
匹配結果:group0:AABC group1:AABC group2:AA group3:BC
匹配結果:group0:AAAAABC group1:AAAAABC group2:AAAAA group3:BC