2013-04-15 64 views
0

初学者的问题。在代码:在Perl中重叠模式匹配

$a = 'aaagggaaa'; 

(@b) = ($a =~ /(a.+)(g.+)/); 

print "$b[0]\n"; 

为什么$b[0]等于aaagg,而不是aaa?换句话说 - 为什么第二组 - (g.+) - 仅匹配从最后的g

+0

如果您想查看Perl正则表达式引擎,请尝试[Regexp :: Debugger](https://metacpan.org/pod/Regexp::Debugger)模块中的'rxrx'实用程序。这是非常酷和教育。 – jreisinger

回答

3

因为第一个.+是“贪婪”,这意味着它会尝试匹配尽可能多的字符。
如果你想表明这种“贪婪”的行为,你可以用.+?代替.+,所以/(a.+?)(g.+)/将返回('aaa','gggaaa')。

也许,你想写/(a+)(g+)/(只有'在第一组和第二个'G')。

1

Perl正则表达式通常匹配可能的最长字符串。

在您的代码中,它与最后的g匹配并返回输出aaagg。如果你想得到输出为aaa,那么你需要使用非贪婪的行为。使用此代码:

$a = 'aaagggaaa'; 
(@b) = ($a =~ /(a.+?)(g.+)/); 
print "$b[0]\n"; 

这将输出:

aaa 

显然,使用question mark使得比赛ungreedy

1

正则表达式,你写道:

($a =~ /(a.+)(g.+)/); 

抓了"a"任何字,因为它可以在一个"g"其次是更多的字符整理。因此,第一个(a.+)只是匹配"aaagg"直到正则表达式的第二部分的匹配:(g.+) =>"gaaa"

@b阵列接收两个比赛"aaagg""gaaa"。所以,$b[0]只是打印"aaagg"

0

通常一个正则表达式是贪婪的。您可以使用?字符将其关闭:

$a = 'aaagggaaa'; 
my @b = ($a =~ /(a.+)(g.+)/); 
my @c = ($a =~ /(a.+?)(g.+)/); 
print "@b\n"; 
print "@c\n"; 

输出:

aaagg gaaa 
aaa gggaaa 

但我不知道这是你想要的!那么abagggbb?您需要aba

1

问题是,第一个.+导致g尽可能地匹配。
为了向您展示真正发生的事情,我修改了您的代码以输出更多说明debug信息。

$ perl -Mre=debug -e'q[aaagggaaa] =~ /a.+[g ]/' 
Compiling REx "a.+[g ]" 
Final program: 
    1: EXACT <a> (3) 
    3: PLUS (5) 
    4: REG_ANY (0) 
    5: ANYOF[ g][] (16) 
    16: END (0) 
anchored "a" at 0 (checking anchored) minlen 3 
Guessing start of match in sv for REx "a.+[g ]" against "aaagggaaa" 
Found anchored substr "a" at offset 0... 
Guessed: match at offset 0 
Matching REx "a.+[g ]" against "aaagggaaa" 
    0 <> <aaagggaaa>   | 1:EXACT <a>(3) 
    1 <a> <aagggaaa>   | 3:PLUS(5) 
            REG_ANY can match 8 times out of 2147483647... 
    9 <aaagggaaa> <>   | 5: ANYOF[ g][](16) 
            failed... 
    8 <aaagggaa> <a>   | 5: ANYOF[ g][](16) 
            failed... 
    7 <aaaggga> <aa>   | 5: ANYOF[ g][](16) 
            failed... 
    6 <aaaggg> <aaa>   | 5: ANYOF[ g][](16) 
            failed... 
    5 <aaagg> <gaaa>   | 5: ANYOF[ g][](16) 
    6 <aaaggg> <aaa>   | 16: END(0) 
Match successful! 
Freeing REx: "a.+[g ]" 

注意,第一个.+被捕捉一切可能与开始了。
然后它必须回溯到g可以匹配。


你可能想要的是一个:

/(a+ )(g+ )/x; 
/(a.+? )(g.+)/x; 
/(a+ )(g.+)/x; 
/(a[^g]+)(g.+)/x; 
/(a[^g]+)(g+ )/x; 
# etc. 

没有更多的信息来自你,那是不可能知道你想要的是什么正则表达式。

真正的正则表达式本身就是一种语言,它比其他Perl更复杂。