分组:用小括号来指定子表达式,然后就可以指定这个子表达式的重复次数,也可以进行其它一些操作。
后向引用:使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。后向引用用于重复搜索前面某个分组匹配的文本。例如,"\1" 引用第1对括号内匹配到的字符串,"\2" 引用第2对括号内匹配到的字符串……
常用分组语法:
分类 | 代码/语法 | 说明 |
---|---|---|
捕获 | (exp) | 匹配exp,并捕获文本到自动命名的组里 |
(?<name>exp) | 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp) | |
(?:exp) | 匹配exp,不捕获匹配的文本,也不给此分组分配组号 | |
零宽断言 | (?=exp) | 匹配exp前面的位置 |
(?<=exp) | 匹配exp后面的位置 | |
(?!exp) | 匹配后面跟的不是exp的位置 | |
(?<!exp) | 匹配前面不是exp的位置 | |
注释 | (?#comment) | 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读 |
实例:
import java.util.regex.*;
public class RegexDemo3 {
public static void printMatch(String reg, String input){
System.out.println("正则:" + reg);
Pattern p = Pattern.compile(reg, Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(input);
int index = 0;
while(m.find()){
System.out.println("分组" + index + ": " + m.group());
for(int i = 0; i<=m.groupCount() ; i++) {
System.out.println("分组子序列" + i + ": " + m.group(i));
}
index++;
}
System.out.println("-------------------------");
}
public static void main(String arg[]) {
String input = "<tr><td>aa</td><td>b b</td><td>cc</td></tr>";
//未指定分组
String reg1 = "<td>.*</td>";
printMatch(reg1, input);
/*
正则:<td>.*</td>
分组0: <td>aa</td><td>b b</td><td>cc</td>
分组子序列0: <td>aa</td><td>b b</td><td>cc</td>
-------------------------
*/
//指定分组、贪婪模式
String reg2 = "<td>(.*)</td>";
printMatch(reg2, input);
/*
正则:<td>(.*)</td>
分组0: <td>aa</td><td>b b</td><td>cc</td>
分组子序列0: <td>aa</td><td>b b</td><td>cc</td>
分组子序列1: aa</td><td>b b</td><td>cc
-------------------------
*/
//指定分组、贪婪模式、后向引用
String reg3 = "<(td)>(.*)</\\1>";
printMatch(reg3, input);
/*
正则:<(td)>(.*)</\1>
分组0: <td>aa</td><td>b b</td><td>cc</td>
分组子序列0: <td>aa</td><td>b b</td><td>cc</td>
分组子序列1: td
分组子序列2: aa</td><td>b b</td><td>cc
-------------------------
*/
//指定分组、非贪婪模式(勉强模式)
String reg4 = "<td>(.*?)</td>";
printMatch(reg4, input);
/*
正则:<td>(.*?)</td>
分组0: <td>aa</td>
分组子序列0: <td>aa</td>
分组子序列1: aa
分组1: <td>b b</td>
分组子序列0: <td>b b</td>
分组子序列1: b b
分组2: <td>cc</td>
分组子序列0: <td>cc</td>
分组子序列1: cc
-------------------------
*/
//(?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号、贪婪模式
String reg5 = "<td>(?:.*)</td>";
printMatch(reg5, input);
/*
正则:<td>(?:.*)</td>
分组0: <td>aa</td><td>b b</td><td>cc</td>
分组子序列0: <td>aa</td><td>b b</td><td>cc</td>
-------------------------
*/
//(?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号、非贪婪模式
String reg6 = "<td>(?:.*?)</td>";
printMatch(reg6, input);
/*
正则:<td>(?:.*?)</td>
分组0: <td>aa</td>
分组子序列0: <td>aa</td>
分组1: <td>b b</td>
分组子序列0: <td>b b</td>
分组2: <td>cc</td>
分组子序列0: <td>cc</td>
-------------------------
*/
//(?=exp) 匹配exp前面的位置、(?<=exp) 匹配exp后面的位置、贪婪模式
String reg7 = "(?<=<td>).*(?=</td>)";
printMatch(reg7, input);
/*
正则:(?<=<td>).*(?=</td>)
分组0: aa</td><td>b b</td><td>cc
分组子序列0: aa</td><td>b b</td><td>cc
-------------------------
*/
//(?=exp) 匹配exp前面的位置、(?<=exp) 匹配exp后面的位置、非贪婪模式
String reg8 = "(?<=<td>).*?(?=</td>)";
printMatch(reg8, input);
/*
正则:(?<=<td>).*?(?=</td>)
分组0: aa
分组子序列0: aa
分组1: b b
分组子序列0: b b
分组2: cc
分组子序列0: cc
-------------------------
*/
//(?!exp) 匹配后面跟的不是exp的位置、非贪婪模式
String reg9 = "(?<=<td>).*?(?=</td>)(?!</td></tr>)";
printMatch(reg9, input);
/*
正则:(?<=<td>).*?(?=</td>)(?!</td></tr>)
分组0: aa
分组子序列0: aa
分组1: b b
分组子序列0: b b
-------------------------
*/
//(?<!exp) 匹配前面不是exp的位置、非贪婪模式
String reg10 = "(?<!<tr><td>)(?<=<td>).*?(?=</td>)";
printMatch(reg10, input);
/*
正则:(?<!<tr><td>)(?<=<td>).*?(?=</td>)
分组0: b b
分组子序列0: b b
分组1: cc
分组子序列0: cc
-------------------------
*/
}
}