通過將部分正則表達式用括號括住來實現分組捕獲的用法大部分人都很熟悉,如/.+(\d+).+/捕獲字符串中的所有數字部分,然后通過組號就可以抽取出各分組匹配的字符文本或者通過反向引用的方式對分組中的文本進行替換。但是除了不同的分組用法以外,正則表達式引擎還提供了一些高級的分組功能,下面介紹部分比較常用的特殊分組:
1、非捕獲分組( non-capturing group)
使用語法:(?:regex)這里的?和:都是語法的組成部分;這種分組正則表達式引擎不會捕獲它所匹配的內容即不會為非捕獲型分組分配組號;
樣例說明:Set(?:Value)?表達式匹配SetValue或者Set,但是不能通過group(1)的方式獲取Value文本串,Set(Value)?則可以獲取的到
語言支持說明:java和javascript都支持
1 public static void noCaptureGroup(){ 2 Pattern pattern = Pattern.compile("(?:(\\d+))?\\s?([a-zA-Z]+)?.+"); 3 String source = "2133 fdsdee4333"; 4 Matcher matcher = pattern.matcher(source); 5 if(matcher.matches()){ 6 for(int i=0;i<=matcher.groupCount();i++){ 7 System.out.println("group "+i+":"+matcher.group(i)); 8 } 9 } 10 }
2、原子分組(Atomic group)
使用語法:(?>regex)這里的?和>都是語法的組成部分;原子分組是貪婪的匹配,當文本和這個分組匹配的成功后,正則表達式引擎在匹配后面的表達式時不會發生回溯行為及盡可能多的匹配,注意這個分組的貪婪行為和++這種貪婪匹配略有不同,++只能對正則表達式字符進行多次貪婪匹配如(bc|b)是沒辦法利用++進行貪婪匹配的而(\w++)可以,如下面代碼中的正則表達式如果換成:(\\d+)\\s+(\\w++)(\\w)匹配則會失敗。
語言支持說明:java支持,javascript不支持
1 public static void atomicGroup(){ 2 Pattern pattern = Pattern.compile("(\\d+)\\s+(?>bc|b)(\\w)"); 3 String source = "543543 bcc"; //而“543543 bc” 卻匹配失敗因為bc已經被原子分組匹配了,當(\\w)進行匹配的時候前面的分組由於是貪婪型匹配所以不會突出以匹配的字符 4 Matcher matcher = pattern.matcher(source); 5 if(matcher.matches()){ 6 for(int i=0;i<=matcher.groupCount();i++){ 7 System.out.println("group "+i+":"+matcher.group(i)); 8 } 9 } 10 }
3、正前向查找分組(Positive lookahead)
使用語法:(?=regex)這里的?和=都是語法的組成部分;可以理解成在正前向分組里面的表達式匹配成功后,正則表達式引擎回溯到正前向分組開始匹配的字符處再進行后面正則表達式的匹配,如果后面的正則表達式也匹配成功,整個匹配過程才算成功。注意這里的正前向查找分組為非捕獲型分組即不會占用分組號
例如下面的樣例代碼中\\s+匹配完數字后面的所有空格后(?=s)和s字符匹配成功,但這個時候指針指向t字符,當進行(\\w+)這個分組匹配時正則表達式引擎會將指針回溯到s處才開始(\\w+)分組的匹配過程。
語言支持說明:java支持,javascript不支持
1 public static void positvieLookaheadGroup(){ 2 Pattern pattern = Pattern.compile("(\\d+)\\s+(?=s)(\\w+)"); 3 String source = "543543 streets"; //"543543 ttreets" 匹配失敗 4 Matcher matcher = pattern.matcher(source); 5 if(matcher.matches()){ 6 for(int i=0;i<=matcher.groupCount();i++){ 7 System.out.println("group "+i+":"+matcher.group(i)); 8 } 9 } 10 }
4、負前向查找分組(Negative lookahead)
使用語法:(?!regex)這里的?和!都是語法的組成部分;這種分組功能和正前向查找分組一樣,唯一的不同就是當前向查找分組里面的正則表達式匹配失敗的時候才繼續后面的匹配過程
語言支持說明:java支持,javascript不支持
1 public static void negtiveLookaheadGroup(){ 2 Pattern pattern = Pattern.compile("(\\d+)\\s+(?!s)(\\w+)"); 3 String source = "543543 ttreets"; //如"543543 streets" 匹配失敗 4 Matcher matcher = pattern.matcher(source); 5 if(matcher.matches()){ 6 for(int i=0;i<=matcher.groupCount();i++){ 7 System.out.println("group "+i+":"+matcher.group(i)); 8 } 9 } 10 }
5、正后向查找分組(Positive lookbehind)
使用語法:(?<=regex)這里的?和<=都是語法的組成部分;可以理解成在正后向查找分組前面的正則表達式匹配成功后,正則表達式引擎從最后的位置往字符串左邊進行回溯然后和(?<=regex)進行匹配,如果匹配失敗則整個匹配過程失敗;如果匹配成功,則將指針移動到正后向查找分組開始進行匹配的位置繼續進行后面正則表達式的匹配過程。注意這里的正前向查找分組為非捕獲型分組即不會占用分組號。
例如下面的樣例代碼中\\s+匹配完數字后面的所有空格后,指針指向s字符,然后進行回溯(?<=\\s)和最后一個空格字符匹配成功,但這個時候指針指向s字符前面的空格,然后正則表達式將指針重新移動到s字符處再進行(\\w+)分組的匹配過程。
語言支持說明:java支持,javascript不支持
1 public static void positiveLookbehandGroup(){ 2 Pattern pattern = Pattern.compile("(\\d+)\\s+(?<=\\s)(\\w+)"); 3 String source = "543543 ttreets"; //"543543 streets" 匹配失敗 4 Matcher matcher = pattern.matcher(source); 5 if(matcher.matches()){ 6 for(int i=0;i<=matcher.groupCount();i++){ 7 System.out.println("group "+i+":"+matcher.group(i)); 8 } 9 } 10 }
6、負后向查找分組(Negative lookbehind)
使用語法:(?<!regex)這里的?和<!都是語法的組成部分;這種分組功能和正負向查找分組一樣,唯一的不同就是當負后向查找分組里面的正則表達式匹配失敗的時候才繼續后面的匹配過程
語言支持說明:java支持,javascript不支持
1 public static void negtiveLookbehandGroup(){ 2 Pattern pattern = Pattern.compile("(\\d+)\\s+(?<!s)(\\w+)"); 3 String source = "543543 ttreets"; //如果正則表達式為(\\d+)\\s+(?<!\\s)(\\w+)則匹配失敗 4 Matcher matcher = pattern.matcher(source); 5 if(matcher.matches()){ 6 for(int i=0;i<=matcher.groupCount();i++){ 7 System.out.println("group "+i+":"+matcher.group(i)); 8 } 9 } 10 }
7、參考資料: