贪婪匹配、非贪婪匹配、占有优先匹配
在基础正则中,那些能匹配多次的量词默认都会匹配最长内容。这种尽量多匹配的行为称为【贪婪匹配】(greedy match)。
例如:
"aa1122ccbb" =~ /a.*c/;
上面正则中的.*
将直接从第二个字母a开始匹配到最结尾的b,因为从第二个字母a开始到最后一个字母b都符合.*
的匹配模式。再然后,去匹配字母c,但因为已经把所有字母匹配完了,只能一个字符一个字符地回退释放,每释放一个字符就匹配一次字母c,发现回退释放到倒数第三个字符c就能满足匹配要求,于是这里的.*
最终匹配的内容是a1122c
。
上面涉及到回溯的概念,表示将那些已经被匹配的内容回退释放。
上面描述的是贪婪匹配行为,还有非贪婪匹配、占有优先匹配。简单描述下:
- 非贪婪匹配:(lazy match)尽可能少地匹配,也叫做懒惰匹配
- 占有优先匹配:(possessive)只要占有就不再交还回溯
有必要搞清楚这几种匹配模式在匹配机制上的区别:
- 贪婪匹配:对于那些量词,将一次性从左到右匹配到最大长度,然后再往回回溯释放
- 非贪婪匹配:对于那些量词,将从左向右逐字符匹配最短长度,然后直接结束这次的量词匹配行为
- 占有优先匹配:先按照贪婪模式匹配,匹配后就【锁】住已匹配内容,不允许进行回溯
贪婪匹配模式、非贪婪匹配模式和占有优先匹配模式对应的量词元字符如下:
(量词后加上?) (量词后加上+)
贪婪匹配量词 非贪婪匹配量词 占有优先匹配量词
------------------------------------------------------
* *? *+
? ?? ?+
+ +? ++
{M,} {M,}? {M,}+
{M,N} {M,N}? {M,N}+
{N} {N}? {N}+
几点需要说明:
- 非贪婪匹配时,
{M,}?
和{M,N}?
等价,因为最多只匹配M次 - Perl不支持
{,N}
的量词模式,所以也没有对应的非贪婪和占有优先匹配模式 - 由于
{N}
是精确匹配N次的量词,所以贪婪与否对最终结果无关紧要,但是却影响匹配时的行为:贪婪匹配最长,需要回溯,非贪婪匹配最短,不回溯,占有优先匹配最长不回溯
看以下示例即可理解贪婪和非贪婪匹配的行为:
my $str="abc123abc1234";
# greedy match
if( $str =~ /(a\w*3)/){
say "$&"; # abc123abc123
}
# lazy match
if( $str =~ /(a\w*?3)/){
say "$&"; # abc123
}
占有优先匹配模式示例:
my $str="abc123abc1234";
if( $str =~ /a\w*+/){ # 成功
say "possessive1: $&";
}
if( $str =~ /a\w*+3/){ # 失败
say "possesive2: $&";
}
从上面第二个示例可知,使用占有优先匹配模式时,它后面不应该跟其他正则表达式,例如a*+x
永远匹配不了东西。