我已经使用perl十年了,但是最近我对使用.?regex感到困惑。它似乎与最小字符数不匹配。有时会给出不同的结果。例如,对于以下字符串:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaammmmmmmmmmmmmmbaaaaaaaaaaaaaaaaaaaaaaaaaaaab和模式:a.?B它匹配两组完整的输入字符串。根据定义,它应该匹配最后一个“ab”。
balp4ylt1#
它不会使a.*?b匹配尽可能少的字符;它使.*匹配尽可能少的字符。由于它只影响.*,所以它对已经匹配的字符没有影响(例如,通过a)。示例缩短为:
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.模式匹配成功。正如您所看到的,它尝试匹配零个字符,这显然是最小的可能匹配。但是当它这样做时,整个模式无法匹配,因此尝试越来越大的匹配,直到整个模式匹配。我尽量避免使用非贪婪修饰语。
.*?
b
aa
'aaab' =~ /a[^a]*b/
如果a真的是更复杂的东西,那么可以使用负前瞻。
'aaab' =~ /a(?:(?!a).)*b/
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>将一次匹配整个字符串,捕获
<tag>(.*)</tag>
text </tag> more text <tag> even more text
在反向参考标号1中。如果将其与<tag>(.*?)</tag>匹配,则会得到两个匹配项:
<tag>(.*?)</tag>
<tag> text </tag>
<tag> even more text </tag>
<tag> text <tag> nested text </tag> back to first level </tag>
然后您会发现<tag>(.*)</tag>再次匹配整个字符串,但<tag>(.*?)</tag>将匹配
<tag> text <tag> nested text </tag>
因为正则表达式引擎是从左到右工作的,这也是正则表达式不是匹配上下文无关语法的“最佳工具”的原因之一。
mm9b1k5b3#
它匹配最少的字符数,从第一个可以匹配的位置开始,这使得正则表达式的其余部分可以匹配。中间部分(从...开始)是正则表达式状态机运行的固有方式。
2w3rbyxf4#
它应该匹配成功匹配整个模式所需的最少字符数(如果有匹配的话)。你能提供一个具体的例子吗?
dldeef675#
我不认为你可以直接匹配ab。通常当.*?不起作用时,它调用[^c]*模式,其中c是字符或字符类。但在本例中,它不起作用:a[^a]*b首先匹配ammmmmmmmmmmb。因此,找到最短匹配的唯一方法是找到所有匹配,然后选择最短的。下面是一个详细的(您说您已经有一段时间没有使用Perl了;--)获得所需结果的方式:
[^c]*
a[^a]*b
ammmmmmmmmmmb
#!/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引擎的一个简单问题。
bakd9h0s6#
请给予一个具体的例子,我们可以用它来重现你正在经历的有问题的行为。您使用了正确的构造,因此可能在查询的其余部分中存在问题。我也遇到过问题,但我总是认为这是由于我的主观分析--即我希望正则表达式按照我的意思进行分析,而不是按照我键入的方式:)
6条答案
按热度按时间balp4ylt1#
它不会使
a.*?b
匹配尽可能少的字符;它使.*
匹配尽可能少的字符。由于它只影响.*
,所以它对已经匹配的字符没有影响(例如,通过a
)。示例缩短为:
发生的情况:
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.模式匹配成功。
正如您所看到的,它尝试匹配零个字符,这显然是最小的可能匹配。但是当它这样做时,整个模式无法匹配,因此尝试越来越大的匹配,直到整个模式匹配。
我尽量避免使用非贪婪修饰语。
如果
a
真的是更复杂的东西,那么可以使用负前瞻。sy5wg1nm2#
意思是
所以在
正则表达式
<tag>(.*)</tag>
将一次匹配整个字符串,捕获在反向参考标号1中。
如果将其与
<tag>(.*?)</tag>
匹配,则会得到两个匹配项:<tag> text </tag>
<tag> even more text </tag>
其中在反向引用数字1中分别仅捕获x1M4 N1 x和x1M5 N1 x。
如果(谢谢Kobi!)您的源文本是
然后您会发现
<tag>(.*)</tag>
再次匹配整个字符串,但<tag>(.*?)</tag>
将匹配因为正则表达式引擎是从左到右工作的,这也是正则表达式不是匹配上下文无关语法的“最佳工具”的原因之一。
mm9b1k5b3#
它匹配最少的字符数,从第一个可以匹配的位置开始,这使得正则表达式的其余部分可以匹配。中间部分(从...开始)是正则表达式状态机运行的固有方式。
2w3rbyxf4#
它应该匹配成功匹配整个模式所需的最少字符数(如果有匹配的话)。你能提供一个具体的例子吗?
dldeef675#
我不认为你可以直接匹配ab。通常当
.*?
不起作用时,它调用[^c]*
模式,其中c是字符或字符类。但在本例中,它不起作用:
a[^a]*b
首先匹配ammmmmmmmmmmb
。因此,找到最短匹配的唯一方法是找到所有匹配,然后选择最短的。下面是一个详细的(您说您已经有一段时间没有使用Perl了;--)获得所需结果的方式:
简而言之,懒惰匹配和获取字符串中的最短匹配是不一样的,而且获取最短匹配也不是Perl(我相信大多数其他语言)使用的rexegp引擎的一个简单问题。
bakd9h0s6#
请给予一个具体的例子,我们可以用它来重现你正在经历的有问题的行为。
您使用了正确的构造,因此可能在查询的其余部分中存在问题。我也遇到过问题,但我总是认为这是由于我的主观分析--即我希望正则表达式按照我的意思进行分析,而不是按照我键入的方式:)