perl .*?正则表达式的实际含义是什么?

uplii1fm  于 2022-11-15  发布在  Perl
关注(0)|答案(6)|浏览(188)

我已经使用perl十年了,但是最近我对使用.?regex感到困惑。
它似乎与最小字符数不匹配。有时会给出不同的结果。
例如,对于以下字符串:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaammmmmmmmmmmmmmbaaaaaaaaaaaaaaaaaaaaaaaaaaaab和模式:a.
?B它匹配两组完整的输入字符串。根据定义,它应该匹配最后一个“ab”。

balp4ylt

balp4ylt1#

它不会使a.*?b匹配尽可能少的字符;它使.*匹配尽可能少的字符。由于它只影响.*,所以它对已经匹配的字符没有影响(例如,通过a)。
示例缩短为:

#01234
'aaab' =~ /a.*?b/

发生的情况:
1.在位置0处,a匹配1个字符(a)。
1.在位置1处,.*?匹配0个字符(空字符串)。
1.在位置1处,b不匹配。⇒后退
1.在位置1处,.*?匹配1个字符(a)。
1.在位置2处,b不匹配。⇒后退
1.在位置1处,.*?匹配2个字符(aa)。
1.在位置3处,b匹配1个字符(b
1.模式匹配成功。
正如您所看到的,它尝试匹配零个字符,这显然是最小的可能匹配。但是当它这样做时,整个模式无法匹配,因此尝试越来越大的匹配,直到整个模式匹配。
我尽量避免使用非贪婪修饰语。

'aaab' =~ /a[^a]*b/

如果a真的是更复杂的东西,那么可以使用负前瞻。

'aaab' =~ /a(?:(?!a).)*b/
sy5wg1nm

sy5wg1nm2#

意思是

.   # match any character except newlines
*   # zero or more times
?   # matching as few characters as possible

所以在

<tag> text </tag> more text <tag> even more text </tag>

正则表达式<tag>(.*)</tag>将一次匹配整个字符串,捕获

text </tag> more text <tag> even more text

在反向参考标号1中。
如果将其与<tag>(.*?)</tag>匹配,则会得到两个匹配项:

  1. <tag> text </tag>
  2. <tag> even more text </tag>
    其中在反向引用数字1中分别仅捕获x1M4 N1 x和x1M5 N1 x。
    如果(谢谢Kobi!)您的源文本是
<tag> text <tag> nested text </tag> back to first level </tag>

然后您会发现<tag>(.*)</tag>再次匹配整个字符串,但<tag>(.*?)</tag>将匹配

<tag> text <tag> nested text </tag>

因为正则表达式引擎是从左到右工作的,这也是正则表达式不是匹配上下文无关语法的“最佳工具”的原因之一。

mm9b1k5b

mm9b1k5b3#

它匹配最少的字符数,从第一个可以匹配的位置开始,这使得正则表达式的其余部分可以匹配。中间部分(从...开始)是正则表达式状态机运行的固有方式。

2w3rbyxf

2w3rbyxf4#

它应该匹配成功匹配整个模式所需的最少字符数(如果有匹配的话)。你能提供一个具体的例子吗?

dldeef67

dldeef675#

我不认为你可以直接匹配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";

简而言之,懒惰匹配和获取字符串中的最短匹配是不一样的,而且获取最短匹配也不是Perl(我相信大多数其他语言)使用的rexegp引擎的一个简单问题。

bakd9h0s

bakd9h0s6#

请给予一个具体的例子,我们可以用它来重现你正在经历的有问题的行为。
您使用了正确的构造,因此可能在查询的其余部分中存在问题。我也遇到过问题,但我总是认为这是由于我的主观分析--即我希望正则表达式按照我的意思进行分析,而不是按照我键入的方式:)

相关问题