先说下组的概念:java
捕获组是把多个字符当一个单独单元进行处理的方法,它经过对括号内的字符分组来建立。正则表达式
例如,正则表达式 (dog) 建立了单一分组,组里包含"d","o",和"g"。spa
捕获组是经过从左至右计算其开括号来编号。例如,在表达式((A)(B(C))),有四个这样的组:翻译
能够经过调用 matcher 对象的 groupCount 方法来查看表达式有多少个分组。groupCount 方法返回一个 int 值,表示matcher对象当前有多个捕获组。code
还有一个特殊的组(group(0)),它老是表明整个表达式。该组不包括在 groupCount 的返回值中。对象
贪婪模式表达式:three
表达式 | 含义 |
---|---|
X? | X,一次或一次也没有 |
X* | X,零次或屡次 |
X+ | X,一次或屡次 |
X{n} | X,刚好 n 次 |
X{n,} | X,至少 n 次 |
X{n,m} | X,至少 n 次,可是不超过 m 次 |
非贪婪模式表达式:文档
表达式 | 含义 |
---|---|
X?? | X,一次或一次也没有 |
X*? | X,零次或屡次 |
X+? | X,一次或屡次 |
X{n}? | X,刚好 n 次 |
X{n,}? | X,至少 n 次 |
X{n,m}? | X,至少 n 次,可是不超过 m 次 |
对于这三种匹配模式也有叫: “最大匹配Greedy”“最小匹配Reluctant”“彻底匹配Possessive”。如今将我对这三种匹配模式的理解写出来,并提供一些例子供你们参考。字符串
一、Greediness(贪婪型): 最大匹配table
X?、X*、X+、X{n,}都是最大匹配。例如你要用“<.+>”去匹配“a<tr>aava </tr>abb
”,也许你所期待的结果是想匹配“<tr>
”,可是实际结果却会匹配到“<tr>aava </tr>
”。这是为何呢?下面咱们跟踪下最大匹配的匹配过程。
①“<”匹配字符串的“<”。
②“.+”匹配字符串的“<tr>aava </tr>ab
”,在进行最大匹配时,它把两个“>”都匹配了,它匹配了全部字符,直到文本的最后字符“b”
③这时,发现不能成功匹配“>”,开始按原路回退,用“a”与“>”匹配,直到“ab”前面的“>”匹配成功。
这就是最大匹配,咱们匹配的时候应该看最后面能匹配到哪。
代码示例: String test = "a<tr>aava </tr>abb "; String reg = "<.+>"; System.out.println(test.replaceAll(reg, "###")); 输出: a###abb
二、Reluctant(Laziness)(勉强型):最小匹配
X?、X*、X+、X{n,}都是最大匹配。好,加个?就成了Laziness匹配。例如X??、X*?、X+?、X{n,}?都是最小匹配,其实X{n,m}?和X{n }?有些多余。
最小匹配意味者,.+? 匹配一个字符后,立刻试一试>的匹配可能,失败了,则.+? 再匹配一个字符,再立刻试一试>的匹配可能。JDK文档中Greedy 和 Reluctant,它是以eat一口来隐喻的,因此翻译成贪吃和(勉强的)厌食最贴切了。不过我喜欢最大匹配、最小匹配的说法。
代码示例: String test = "a<tr>aava </tr>abb "; String reg = "<.+?>"; System.out.println(test.replaceAll(reg, "###")); 输出: a###aava ###abb 和上面的不一样是匹配了两处。
三、Possessive(占有型):彻底匹配
与最大匹配不一样,还有一种匹配形式:X?+、X*+、X++、X{n,}+等,成为彻底匹配。它和最大匹配同样,一直匹配全部的字符,直到文本的最后,但它不禁原路返回。也就是说,一口匹配,搞不定就算了,到也干脆,偶喜欢。
代码示例: String test = "a<tr>aava </tr>abb "; String test2 = "<tr>"; String reg = "<.++>"; String reg2 = "<tr>"; System.out.println(test.replaceAll(reg, "###")); System.out.println(test2.replaceAll(reg2, "###")); 输出: a<tr>aava </tr>abb ###
可见。彻底匹配是最严格的,必须整个字符串匹配才行。
实例: 获取下面字符串中的大括号中的内容:
{one}{two}{three}
能够这样:
String s = "{one}{two}{three}"; //由于默认为贪婪模式,因此若是没有使用显示()组中的元素不能为大括号([^}]*),而是使用(.*), //那么会匹配的字符串为:one}{two}{three Pattern p = Pattern.compile("\\{([^}]*)\\}"); Matcher m = p.matcher(s); while (m.find()) { System.out.println(m.group(1));//第一次匹配成功是one,第二次匹配成功是two,第三次匹配为three }
输出
one two three
若是想要三个大括号中的 内容一块儿输出,能够这样:
String s = "{one}{two}{three}"; Pattern p = Pattern.compile("\\{([^}]*)\\}\\{([^}]*)\\}\\{([^}]*)\\}"); Matcher m = p.matcher(s); while (m.find()) { System.out.println(m.group(1) + ", " + m.group(2) + ", " + m.group(3));//获取该次匹配中组(),正则表达式中只有一个(),即只分了一个组 }
输出
one, two, three
关于组的实例:
import java.util.regex.Matcher; import java.util.regex.Pattern; public class RegexMatches { public static void main( String args[] ){ // 按指定模式在字符串查找 String line = "This order was placed for QT3000! OK?"; String pattern = "(\\D*)(\\d+)(.*)"; // 建立 Pattern 对象 Pattern r = Pattern.compile(pattern); // 如今建立 matcher 对象 Matcher m = r.matcher(line); if (m.find( )) { //每次匹配成功以后,表示利用pattern 获取到了匹配的字符串,而pattern 中有三个小括号,即有三个 //组,那么每次匹配成功确定有group(1),group(2),group(3),group(0)是它老是表明整个表达式 System.out.println("Found value: " + m.group(0) ); System.out.println("Found value: " + m.group(1) ); System.out.println("Found value: " + m.group(2) ); System.out.println("Found value: " + m.group(3) ); } else { System.out.println("NO MATCH"); } } }
运行结果以下:
Found value: This order was placed for QT3000! OK? Found value: This order was placed for QT Found value: 3000 Found value: ! OK?