標籤:
Regex是什嗎?
Regex是一種強大而靈活的文本處理工具。初學Regex時,其文法是一個痛點,但它確實是一種簡潔、動態語言。Regex提供了一種完全通用的方式,能夠解決各種字串處理相關的問題:匹配、選擇、編輯以及驗證。一般來說,Regex就是以某種方式來描述字串。
日常例子
在文本中尋找“halu126”,我們通常會在尋找框中輸入“halu126”,這就是一個最簡單的Regex的例子,使用精確的匹配這樣的字串,如果我 們即想在文本中找到“halu126”,又想找到“Halu126”,卻不想找到“aaaHalu126bbbb”中的“Halu126”,該怎麼辦?
在linux中我們想查想列出所有的Java源檔案,通常會在終端中輸入:ls -all *.java,其中“*”是叫做萬用字元,而Regex比萬用字元更牛,它能更精確的描述你的需求。
Regex的構造摘要
構造 |
匹配 |
字元 |
X |
字元X |
| \\\\ |
反斜線字元 |
\t |
定位字元 |
\n |
分行符號 |
\r |
斷行符號符 |
字元類 |
[abc] |
a、b 或 c(簡單類) |
[^abc] |
任何字元,除了 a、b 或 c(否定) |
[a-zA-Z] |
a 到 z 或 A 到 Z,兩頭的字母包括在內(範圍) |
[a-d[m-p]] |
a 到 d 或 m 到 p:[a-dm-p](並集) |
[a-z&&[def]] |
d、e 或 f(交集) |
[a-z&&[^bc]] |
a 到 z,除了 b 和 c:[ad-z](減去) |
預定義字元類 |
. |
任何字元 |
\d |
數字:[0-9] |
\D |
非數字:[^0-9] |
\s |
空白字元:[\t\n\x0B\f\r] |
\S |
非空白字元:[^\s] |
\w |
單詞字元:[a-zA-Z_0-9] |
\W |
非單詞字元:[^\w] |
邊界匹配器 |
^ |
行的開頭 |
$ |
行的結尾 |
\b |
單詞邊界 |
\B |
非(單詞邊界) |
量詞 |
X? |
X,一次或一次也沒有 |
X* |
X,零次或多次 |
X+ |
X,一次或多次 |
| X{n} |
X,恰好n次 |
| X{n,} |
X,至少n次 |
| X{n,m} |
X,至少n次,但是不超過m次 |
Logical運算子 |
XY |
X後跟Y |
X|Y |
X或者Y |
(X) |
X,作為擷取的群組 |
組和捕獲
擷取的群組可以通過從左至右計算其開括弧來編號。例如,在運算式中((A)(B(C)))中,存在四個這樣的組
| 1 |
((A)(B(C))) |
2 |
(A) |
3 |
(B(C)) |
4 |
(C) |
Java語言中Regex的不同處
在其他語言中,“ \\”表示“我想在Regex中插入一個普通的(字面上的)反斜線,請不要給它任何特殊的意義。”在Java語言中,“\\”表示“我要插入一個Regex的反斜線,所以其後的字元具有特殊的意思。”例如:“\\d”表示Java語言中Regex的一位元字。“\\\\”表示一個普通的反斜線。不過換行和定位字元之類的東西只需要使用單反斜線:“\n\t”。
量詞的類型:
量詞:描述了一個模式吸收(匹配)輸入文本的方式,也叫做重複限定符。
貪婪型:量詞總是貪婪的,除非有其他的選項被設定。貪婪運算式會為所有可能的模式發現儘可能多的匹配。
勉強型:用問號指定,這個量詞匹配滿足模式所需的最少字元數。因此也稱作懶惰的、最少匹配的、非貪婪的、或不貪婪的。
佔有型:Java中專屬的。其他語言沒有。當Regex被應用於字元序列時,它會產生相當多的狀態,以便在匹配失敗時可以回溯。而“佔有的”量詞並不儲存這些中間狀態,因此他們可以防止回溯。他們常常用於防止Regex失控,因此可以使Regex執行起來更有效。
Greedy數量詞 |
Reluctant數量詞 |
Possessive數量詞 |
X? |
X?? |
X?+ |
X* |
X*? |
X*+ |
X+ |
X+? |
X++ |
X{n} |
X{n}? |
X{n}+ |
X{n,} |
X{n,}? |
X{n,}+ |
X{n,m} |
X{n,m}? |
X{n,m}+ |
量詞作用的運算式通常必須要使用圓括弧括起來。
String類中使用Regex的方法
matches(String regex)
split(String regex)
split(String regex, int limit)
replaceFirst(String regex, String replacement)
repalceAll(String regex, String replacement)
Java語言中表示Regex的類
在Java語言中與Regex相關的類都放在java.util.regex包。
- *Pattern類:*pattern對象是一個Regex的編譯表示。Pattern類沒有公用構造方法。要建立一個Pattern對象,你必須首先調用其公用靜態編譯方法,它返回一個Pattern對象。該方法接受一個Regex作為它的第一個參數。
- *Matcher類:*Matcher對象是對輸入字串進行解釋和匹配操作的引擎。與Pattern類一樣,Matcher也沒有公用構造方法。你需要調用Pattern對象的matcher方法來獲得一個Matcher對象。
- *PatternSyntaxException:*PatternSyntaxException是一個非強制異常類,它表示一個Regex模式中的語法錯誤。
指定為字串的Regex必須首先被編譯為此類的執行個體。然後,可將得到的模式用於建立Matcher對象,依照Regex,該對象可以與任一字元序列匹配。執行匹配所涉及的所有狀態都駐留在匹配器中,所以多個匹配器可以共用同一模式。
因此,典型的調用順序是
1 Pattern pattern = Pattern.compile("a*b");2 Matcher matcher= pattern("aaaaaaab");3 matcher.XXX();
一個簡單的代碼如下:
1 public class TestRegularExpression { 2 public static void main(String[] args) { 3 if(args.length < 2) { 4 print("Usage:\njava TestRegularExpression " + 5 "characterSequence regularExpression+"); 6 System.exit(0); 7 } 8 print("Input: \"" + args[0] + "\""); 9 for(String arg : args) {10 print("Regular expression: \"" + arg + "\"");11 Pattern p = Pattern.compile(arg);12 Matcher m = p.matcher(args[0]);13 while(m.find()) {14 print("Match \"" + m.group() + "\" at positions " +15 m.start() + "-" + (m.end() - 1));16 }17 }18 }19 }Pattern和Matcher類中常用的方法
1 //使用Pattern類的靜態方法compile來編譯Regex,它會根據Regexregex產生一個Pattern對象。 2 Pattern pattern = Pattern.compile(String regex) 3 //檢查regex是否匹配整個CharSequence類型的input參數 4 Pattern.matches(String regex, CharSequence input) 5 //從匹配了regex的地方分割輸入字元序列input 6 pattern.split(CharSequence input) 7 //同String.split() 8 pattern.split(CharSequence input, int limit) 9 //根據模板pattern產生input的匹配器matcher10 Matcher matcher = pattern.matcher(CharSequence input);11 //從字元序列的開始位置(0位字元)迭代的向前遍曆字元序列,找到匹配模式的部分12 matcher.find()13 //從字元序列的第start位字元開始(以第start位字元作為搜尋的起點)迭代的向前遍曆字元序列,找到匹配模式的部分14 matcher.find(int start)15 //判斷整個輸入字元序列是否匹配Regex模式16 matcher.matches()17 //判斷該字元序列(不必是整個字元序列)的開始部分是否能夠匹配模式18 matcher.lookingAt()19 //該匹配器的模式中的分組數目20 matcher.groupCount()21 //返回前一次匹配操作(例如find())的第0組(即整個匹配)22 matcher.group()23 //返回在前一次操作期間指定的組號,如果沒有指定的組,返回null24 matcher.group(int group)25 //26 matcher.start()27 //返回前一次匹配操作中尋找到的組的起始索引28 matcher.start(int group)29 matcher.end()30 //返回前一次匹配操作中尋找到的組的最後一個字元索引加一的值31 matcher.end(int group)32 //將matcher對象重新設定到當前字元序列的起始位置33 matcher.reset()34 將現有的matcher對象應用到一個新的字元序列35 matcher.reset(CharSequence input)
使用Regex時要注意的事兒
要匹配一種情況,我們可以寫出多個可行的Regex,當然了,我們的目的並不是編寫最難理解的Regex,而是盡量編寫能夠完成任務的、最簡單以及最必要的Regex。
參考
- Java編程思想
- JDK API文檔
- Regex30分鐘入門教程
- RUNOOB中關於Regex的介紹
Java語言中的Regex