有时我们需要获取的内容前后必须是特定内容,但又不获取这些特定内容的时候,此时我们应该用零宽断言,零宽断言简单来理解就是,正则表达式中应该匹配这些内容,但是这些内容不消耗匹配的字符串(如果不用零宽断言存在的问题是:特定内容前后的字符被消耗,导致字符串进行进一步匹配的时候,有些字符消耗了导致匹配不上)
简单来说:当我们从0开始匹配,如果最开始用到零宽断言,那么匹配上之后继续从0开始,如果后面还是零宽断言,匹配完当前零宽断言之后还是从0开始匹配,直到非零宽断言index才开始移动
String str = "abcefabchg";
Pattern p = Pattern.compile("^(?=a)(?=ab)abc.{1}");
Matcher m = p.matcher(str);
while(m.find()){
System.out.print(m.group());
}
输出结果:abce
eg:reg="^(?=a)(?=ab)abc.{1}" str=“abcefabchg” 首先从0开始匹配 ^,匹配成功,然后继续从ab中的a开始匹配,匹配上(?=a)但是此时不消耗字符,所以(?=ab)继续从ab中的a开始匹配,匹配上,此时仍然匹配上且不消耗字符,所以a继续从ab中的a开始匹配,匹配到abce,然后继续下一轮,此时是从abcefabchg中的f开始匹配,因为前面的都匹配上了且已经被消耗了,所以匹配不上。
捕获非捕获
*(?:)
表示非捕获分组,和捕获分组唯一的区别在于,非捕获分组匹配的值不会保存起来
一个括号就是一个分组,有时候我们只需要外层最大的几个分组,那么里层的许许多多的小的分组就可以用非捕获组来表示,这样我们才好根据group来取最外面的几个大的分组。
获取非获取(零宽断言)
? 询问
= 是否匹配后面的正则表达式
! 是否不匹配后面的表达式
< 从昨天开始匹配
以上组合出现下面四种场景:
?=
正向肯定预查(look ahead positive assert),匹配pattern前面的位置
eg:“Windows(?=95|98|NT|2000)“能匹配"Windows2000"中的"Windows”,但不能匹配"Windows3.1"中的"Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
?!
正向否定预查(look ahead negative assert),在任何不匹配pattern的字符串开始处匹配查找字符串
eg:例如"Windows(?!95|98|NT|2000)“能匹配"Windows3.1"中的"Windows”,但不能匹配"Windows2000"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
?<=
反向肯定预查(look behind positive assert),与正向肯定预查类似,只是方向相反。
eg:"(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中的"Windows",但不能匹配"3.1Windows"中的"Windows"。
?<!
反向否定预查(look behind negative assert),与正向否定预查类似,只是方向相反。
eg:"(?<!95|98|NT|2000)Windows"能匹配"3.1Windows"中的"Windows",但不能匹配"2000Windows"中的"Windows"。