我已经使用Perl十年了。但是最近我对使用.*?正则表达式感到困惑。
它似乎不能匹配最少数量的字符。有时它会给出不同的结果。
例如,对于这个字符串:aaaaaaaaaaaaaaaaaaaaaaammmmmmmmmmmbaaaaaaaaaaaaaaaaaaaaaab 和模式:a.*?b,它在两个组中完全匹配输入字符串。根据定义,它应该匹配最后的 "ab"。
a.*?b
匹配尽可能少的字符;它会导致.*
匹配尽可能少的字符。由于它只影响.*
,它对已经匹配的内容(即由a
匹配的内容)没有影响。#01234
'aaab' =~ /a.*?b/
a
匹配了1个字符(a
)。
2. 在位置1,.*?
匹配了0个字符(空字符串)。
3. 在位置1,b
无法匹配。⇒ 回溯
4. 在位置1,.*?
匹配了1个字符(a
)。
5. 在位置2,b
无法匹配。⇒ 回溯
6. 在位置1,.*?
匹配了2个字符(aa
)。
7. 在位置3,b
匹配了1个字符(b
)。
8. 模式匹配成功。'aaab' =~ /a[^ab]*b/
a
确实是更复杂的东西,那么可以使用负向前瞻。'aaab' =~ /a(?:(?!a|b).)*b/
. # match any character except newlines
* # zero or more times
? # matching as few characters as possible
So in
<tag> text </tag> more text <tag> even more text </tag>
<tag>(.*)</tag>
会一次性匹配整个字符串,并捕获其中的内容。 text </tag> more text <tag> even more text
在反向引用编号1中。
如果您使用<tag>(.*?)</tag>
进行匹配,您将获得两个匹配项:
<tag> text </tag>
<tag> even more text </tag>
分别仅捕获text
和even more text
在反向引用编号1中。
如果(感谢Kobi!)您的源文本是
<tag> text <tag> nested text </tag> back to first level </tag>
如果你使用<tag>(.*)</tag>
进行匹配,你会发现它会再次匹配整个字符串,但是使用<tag>(.*?)</tag>
则只会匹配
<tag> text <tag> nested text </tag>
由于正则表达式引擎从左到右工作,这就是为什么正则表达式不是匹配上下文无关文法的最佳工具之一。
<tag><tag>text</tag>
- 在“懒惰”和“最优化最小化”之间存在混淆。 - Kobi它匹配最少数量的字符,从第一个能匹配的位置开始,这使得正则表达式的其余部分可以匹配。那个中间部分(从...开始)是正则表达式状态机运作方式的本质。(为了进一步澄清而编辑)
.*?
并不能保证最短的匹配,而是在该位置上消耗尽可能少的元素,同时仍然允许其余的正则表达式匹配。 - sarnoldaaaaaaaaaaaaaaaaaaaaaaaaaab
作为第二个匹配项。 - Tim Pietzcker我认为在你的情况下不能直接匹配ab。通常当.*?
无法工作时,需要使用[^c]*
模式,其中c是一个字符或字符类。这可以防止误匹配。
但在这种情况下,它不起作用:a[^a]*b
首先匹配ammmmmmmmmmmb
。因此,找到最短匹配的唯一方法是找到所有匹配,然后选择最短的。
以下是一种详细的(你说你有一段时间没有使用Perl了;--)获取所需结果的方法:
#!/usr/bin/perl
use strict;
use warnings;
use List::Util qw(reduce); # see List::Util docs for what reduce does
my $s= "aaaaaaaaaaaaaaaaaaaaaaammmmmmmmmmmbaaaaaaaaaaaaaaaaaaaaaab";
my $RE= qr/a[^a]*b/;
print "regexp: $RE\n"; # ammmmmmmmmmmb
print "single match:\n";
if( $s=~ m{($RE)}) { print " $1\n"; }
print "all matches (loop):\n"; # ammmmmmmmmmmb \n ab
while( $s=~ m{($RE)}g)
{ print " - $1\n"; }
print "all matches (in an array):\n"; # ammmmmmmmmmmb - ab
my @matches= $s=~ m{(a[^a]*b)}g;
if( @matches) { print " ", join( " - ", @matches), "\n"; }
print "\nshortest match: "; # ab
print reduce { length $a < length $b ? $a : $b } @matches;
print "\n";
它应该匹配最少数量的字符,以便整个模式能够成功匹配(如果有匹配的话)。你能提供一个具体的例子,证明它没有做到这一点吗?
.*?
不总是匹配最少数量的字符,而不是?
的目的是什么。 - Ted Hopp.*?
的工作原理,你就可以轻松回答那个问题。在这种情况下,可能是同一用户提出的这个问题的概括:https://dev59.com/glXTa4cB1Zd3GeqP2H2I - Kobi