贪婪的算子结果在正面和负面前瞻性方面有所不同吗?

时间:2015-01-12 11:27:05

标签: regex perl

我对贪婪的操作员的前瞻性和消极前瞻感到困惑。

正向前瞻

脚本

foreach (<DATA>){
$_ = m/AAA.+(?=BBB)/g;
print "$&\n";
} 
__DATA__
AAA 1121 BBB
AAA 443  CCC
AAA 4431 BBB
ABC 321  EACA
AAA 321  BBB
ACD 431 MAKN
AAA 751  ABC

它的输出

AAA 1121 

AAA 4431 

AAA 321  

否定前瞻

foreach (<DATA>){
$_ = m/AAA.+(?!BBB)/g; 
print "$&\n";
} 

它的输出

AAA 1121 BBB
AAA 443  CCC
AAA 4431 BBB

AAA 321  BBB

AAA 751  ABC

在执行negative lookahed时,请不要考虑(?!BBB)。因为我使用了(?!BBB)之前的贪婪运算符。在这种情况下,前瞻性贪婪算子会考虑(?=BBB)。这就是为什么给出不同的结果?

我可以通过代码$_ = m/AAA\s\d+(?!.+BBB)/g;轻松实现OP。

但我不知道代码的执行情况是什么?

2 个答案:

答案 0 :(得分:8)

让我们考虑第一个例子:

AAA 1121 BBB
\_/\_______/^
 |     |    |
 |     |    +--- this (the empty string right there) satisfies (?!BBB)
 |     |
 |     +-------- matched by .+
 |     
 +-------------- matched by AAA

这是因为贪婪的.+消费1121 BBB 包括 BBB。在消耗了剩下的行后,将检查(?!BBB)对剩余的空字符串。这个空字符串满足(?!BBB),因为BBB后面没有它?


否定前瞻

算法执行如下。 ^当前位置(字符串中有当前位置,模式中的当前位置 (种类)

  1. 初始状态:

    AAA 1121 BBB          AAA.+(?!BBB)
    ^                     ^
    
  2. 匹配AAA

    AAA 1121 BBB          AAA.+(?!BBB)
       ^                     ^
    
  3. 匹配.+

    AAA 1121 BBB          AAA.+(?!BBB)
                ^              ^
    
  4. 检查(?!BBB)

    AAA 1121 BBB          AAA.+(?!BBB)
                ^                     ^
    
  5. 此位置没有BBB匹配=&gt;成功了!

    AAA 1121 BBB
    \__________/
    

  6. 积极向前看

    现在,让我们看看完全 AAA.+(?=BBB)产生匹配的原因:

    1. 初始状态:

      AAA 1121 BBB          AAA.+(?=BBB)
      ^                     ^
      
    2. 匹配AAA

      AAA 1121 BBB          AAA.+(?=BBB)
         ^                     ^
      
    3. 匹配.+

      AAA 1121 BBB          AAA.+(?=BBB)
                  ^              ^
      
    4. 检查(?=BBB)

      AAA 1121 BBB          AAA.+(?=BBB)
                  ^              ^
      

      此位置没有BBB匹配=&gt;回溯(消耗少{char} .+

    5. 检查(?=BBB)

      AAA 1121 BBB          AAA.+(?=BBB)
                 ^               ^
      

      此位置没有BBB匹配=&gt;回溯(消耗少{char} .+

    6. 检查(?=BBB)

      AAA 1121 BBB          AAA.+(?=BBB)
                ^                ^
      

      此位置没有BBB匹配=&gt;回溯(消耗少{char} .+

    7. 检查(?=BBB)

      AAA 1121 BBB          AAA.+(?=BBB)
               ^                        ^
      
    8. 我们在这个位置确实有BBB个匹配=&gt;成功了!

      AAA 1121 BBB
      \_______/
      

答案 1 :(得分:2)

在两种情况下它的工作方式没有区别,.+在两种情况下都是贪婪的。

AAA.+(?=BBB)AAA 1121 BBB进行匹配时,.+ AAA <spc>1121<spc>之后的(?=BBB)可以匹配AAA.+(?!BBB)。任何更长的时间都会导致AAA 1121 BBB失败。

.+AAA进行匹配时,<spc>1121<spc>BBB BBB (?!BBB)之后的(?:(?!STRING).)*可以匹配STRING。作为字符串的其余部分,它可能不再匹配任何东西。

请注意,字符串的结尾不是[^CHAR]*,因此CHAR匹配字符串的末尾。


say $1 if /^(AAA\s+\S+)\s+(?:(?!BBB)\s)*\z/; my @F = split; say "$F[0] $F[1]" if $F[0] eq 'AAA' && $F[2] ne 'BBB'; ,{{1}}是{{1}}。

我和

一起去
{{1}}

第二个想法,我跟

一起去
{{1}}