2013-04-15 63 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更復雜。