什么。*?正则表达式实际上是指

时间:2011-03-23 06:52:54

标签: regex perl

我已经使用perl十年了。但最近我对使用它感到困惑。*?正则表达式。

它似乎与最小字符数不匹配。有时会产生不同的结果。

例如,对于这个字符串:aaaaaaaaaaaaaaaaaaaaaaammmmmmmmmmbaaaaaaaaaaaaaaaaaaaaaa和pattern:a。*?b它匹配两组中的完整输入字符串。根据定义,它应该与最后的“ab”相匹配。

6 个答案:

答案 0 :(得分:8)

示例缩写为:

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

会发生什么:

  1. a匹配a
  2. .*?匹配尽可能少的字符数(0),匹配空字符串。
  3. b无法匹配。 ⇒回溯
  4. .*?匹配尽可能少的字符数(1),匹配a
  5. b无法匹配。 ⇒回溯
  6. .*?匹配尽可能少的字符数(2),匹配aa
  7. b匹配b
  8. 模式匹配成功。
  9. 我尽量避免使用非贪婪的修饰符。

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

    如果a确实更复杂,那么就可以使用否定前瞻。

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

答案 1 :(得分:6)

这意味着

.   # 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>
  3. 仅分别在反向引用号1中捕获texteven more text

    如果(感谢Kobi!)你的源文本是

    <tag> text <tag> nested text </tag> back to first level </tag>
    

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

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

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

答案 2 :(得分:4)

它匹配最小数量的字符,从可匹配的第一个位置开始,这允许正则表达式的其余部分匹配。中间部分(从...开始)是正则表达式状态机运行方式所固有的。 (编辑进一步澄清)

答案 3 :(得分:1)

它应该匹配整个模式成功匹配所需的最小字符数(如果匹配则完全匹配)。你能提供一个不这样做的具体例子吗?

答案 4 :(得分:1)

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

简而言之,延迟匹配与获取字符串中的最短匹配不同。对于rexegp引擎Perl(我相信大多数其他语言)使用这种最短匹配并不是一个简单的问题。

答案 5 :(得分:0)

请举一个具体的例子,我们可以用它来重现您遇到的有问题的行为。

您正在使用正确的构造,因此可能在您的查询的其余部分中存在问题。我也遇到过问题,但总是想到这是由于我的如意解析 - 即我希望正则表达式解析我的意思,而不是我输入的方式:)