0

一个初学者的问题。在代码中:

$a = 'aaagggaaa';

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

print "$b[0]\n";

为什么$b[0]等于aaagg和不等于aaa?换句话说 - 为什么第二组 -(g.+)只从最后一个匹配g

4

5 回答 5

3

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

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

于 2013-04-15T08:23:57.930 回答
1

问题是第一个.+导致g尽可能向右匹配。
为了向您展示实际发生的情况,我修改了您的代码以输出更多说明性的调试信息。

$ 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 的其他部分更复杂。

于 2013-04-15T17:27:48.653 回答
1

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

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

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

它将输出:

aaa

显然,使用question mark会使匹配变得不贪婪

于 2013-04-15T08:30:46.587 回答
1

你写的正则表达式:

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

尽可能捕捉"a"and 任何单词,以一个"g"结尾,然后是更多字符。所以第一个(a.+)匹配"aaagg",直到你的正则表达式的第二部分匹配:(g.+)=>"gaaa"

@b数组接收两个匹配项"aaagg""gaaa"。所以,$b[0]只打印"aaagg".

于 2013-04-15T08:31:58.337 回答
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吗?

于 2013-04-15T11:46:16.387 回答