- 一、Greediness(贪婪型)
- (一)贪婪模式示例
- (二)贪婪模式的匹配过程(贪婪模式的回溯)
- 二、Reluctant(勉强型)
- (一)非贪婪模式示例
- (二)非贪婪模式的匹配过程
- 三、Possessive(占有型)
- (一)占有模式示例
- (二)占用模式的匹配过程
贪婪模式,最大匹配,匹配优先。
在 Greediness
的模式下,会尽量大范围的匹配,直到匹配了整个内容,这时发现匹配不能成功时,开始回退缩小匹配范围,直到匹配成功。
默认情况下,所有的限定符都是贪婪模式,表示尽可能多的去捕获字符。
(一)贪婪模式示例正则表达式://
,这个正则表达式的含义:匹配以 为尾,中间是
1
个或多个任意字符的字符串。 被查找的字符串:aaava abb
匹配的结果:aava
Java 代码举例如下:
String test = "aaava abb";
String reg = "";
System.out.println(test.replaceAll(reg, "###"));
说明:上面的 Java 代码会将字符串 aaava abb
中所有符合正则式的字符串替换为 ###
,最后输出结果为:a###abb
。其实 和
也符合正则式
//
,但是贪婪呀,因为被匹配的字符串还很长,所以会继续匹配下去,直到捕获到最多且匹配成功为止。
注意:正则表达式的限定符(量词)?
、+
、*
以及区间限定符 {n,m}
默认都是贪婪模式。
再举个例子:
String test = "foooood";
String reg ="o{1,}";
System.out.println(test.replaceAll(reg, "#"));
上面的 Java 代码会一次匹配全部的字符 o
,什么意思?就是说整个正则表达式单次匹配成功中,会匹配尽可能多的字符,而 ooooo
是符合正则式 o{1,}
的,所以在单次匹配成功中就全部捕获了,所以最后输出的结果为:f#d
。如果你想得到这样的结果:f#####d
,应该怎么写表达式呢?那么表达式成功匹配一个 o
时,就算整个正则表达式匹配成功 1 次,那么成功匹配 5 个 o
,就算整个正则式匹配成功了 5 次,这样就会执行 5 次替换,最后 ooooo
就会替换成 #####
,我们看下面的示例。
String test = "foooood";
String reg ="o{1,}?";
System.out.println(test.replaceAll(reg, "#"));
在区间量词后添加个问号 ?
,就是非贪婪模式,那么匹配了一个 o
,就算正则式成功匹配一次,然后正则式又重新从正则式的第一个子表达式对被匹配的字符串已经成功匹配的下个字符开始继续匹配,直到无字符可匹配为止。
贪婪模式的正则表达式去匹配字符串"aaavaabb",会匹配到"aava",下面说一下贪婪模式的具体匹配过程。
首先
中的
。
>
尝试匹配字符串结尾失败,向前查找可回溯状态,控制权交给 .*
,.*
让出一个字符,也就是字符串结尾的"b",然后将控制权交给 >
。>
尝试匹配字符串结尾的"b",匹配失败,再次向前查找可回溯状态,将控制权交给 .*
…
重复以上过程,直到 .*
让出第十个字符">",>
匹配第十个字符">"成功,从而整个正则表达式匹配成功一次。 获得控制权后,会尝试匹配第四个字符"a",匹配失败,向前查找可回溯状态,于是
.+?
重新取得控制权,.+?
记录的回溯位置是第 3 个字符“>”,于是 .+?
会去匹配回溯位置的下一个字符,也就是第 4 个字符“a”,匹配成功后再次记录下回溯状态,然后再次将控制权交给 >
。>
获得控制权后,会尝试匹配第五个字符"a",结果匹配失败,再次向前查找可回溯状态…
就这样重复上述过程,直到 .+?
匹配到了第九个字符"/",将控制权交给 >
。>
匹配第十个字符">",终于匹配成功了,从而整个正则表达式匹配成功一次,记录下匹配结果。因为每个字符只能被正则匹配一次,所以 。
>
获得控制权后,尝试匹配字符串结尾,结尾无字符,匹配失败。因为没有回溯状态可查找,>
直接匹配失败,从而整个正则表达式 匹配失败。
带区间的类似 .{m,n}+
也是不带回溯状态的,需要注意,具体匹配过程类似上文,就不详述了。
总结:把东西全部吃掉了,也不吐出来,结果导致别人没得吃