传送门: http://blog.sina.com.cn/s/blog_4b9694cf0100cghj.html
X? | X,一次或一次也没有 |
X* | X,零次或多次 |
X+ | X,一次或多次 |
X{n} | X,恰好 n 次 |
X{n,} | X,至少 n 次 |
X{n,m} | X,至少 n 次,但是不超过 m 次 |
但是我们如果要对多个字符进行重复怎么办呢?此时我们就要用到分组,我们可以使用小括号"()"来指定要重复的子表达式,然后对这个子表达式进行重复,例如:(abc)?表示0个或1个abc 这里一个括号的表达式就表示一个分组。
捕获组
捕获组可以通过从左到右计算其开括号来编号。例如,在表达式((A)(B(C))) 中,存在四个这样的组:
1 ((A)(B(C))) 2 \A 3 (B(C)) 4 (C)
组零始终代表整个表达式
之所以这样命名捕获组是因为在匹配中,保存了与这些组匹配的输入序列的每个子序列。捕获的子序列稍后可以通过 Back 引用在表达式中使用,也可以在匹配操作完成后从匹配器检索。
非捕获组
| |
| |
(?=X) | |
(?!X) | |
(?<=X) | |
(?<!X) | |
|
这四个非捕获组用于匹配表达式X,但是不包含表达式的文本。
(?=X) | 零宽度正先行断言。仅当子表达式 X 在此位置的右侧匹配时才继续匹配。例如,\w+(?=\d)与后跟数字的单词匹配,而不与该数字匹配。此构造不会回溯。 |
(?!X) | 零宽度负先行断言。仅当子表达式 X 不在此位置的右侧匹配时才继续匹配。例如,例如,\w+(?!\d)与后不跟数字的单词匹配,而不与该数字匹配。 |
(?<=X) | 零宽度正后发断言。仅当子表达式 X 在此位置的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 后面的 99的实例匹配。此构造不会回溯。 |
(?<!X) | 零宽度负后发断言。仅当子表达式 X不在此位置的左侧匹配时才继续匹配。例如,(?<!19)99 与不跟在 19 后面的 99的实例匹配 |
举例:
-
Pattern p = Pattern.compile("(?<!c)a(\\d+)bd"); -
Matcher m = p.matcher("da12bca3434bdca4343bdca2 34bm"); -
while(m.find()){ -
System.out.println(m.group(1));//我们只要捕获组1的数字即可。结果 3434 -
System.out.println(m.group(0)); //0组是整个表达式,看这里,并没有提炼出(?<!c)的字符 。结果 a3434bd -
}
最后用了两种方法解决:
解法一:比较笨的方法,没有使用非捕获组:
解法二:使用非捕获组
一个正则表达式就可解决。
再次印证了正则表达式的重要性。