代码之家  ›  专栏  ›  技术社区  ›  Tom Corelis

Perl:块中的多个全局或“分离”正则表达式条件导致无限循环?

  •  5
  • Tom Corelis  · 技术社区  · 14 年前

    我正在学习Perl并注意到一个非常奇怪的怪癖——试图在while循环中匹配多个regex条件之一会导致该循环无限长:

    #!/usr/bin/perl
    
    my $hivar = "this or that";
    
    while ($hivar =~ m/this/ig || $hivar =~ m/that/ig) {
            print "$&\n";
    }
    

    这个程序的输出是:

    this
    that
    that
    that
    that
    [...]
    

    我想知道这是为什么?有没有比这更笨拙的解决方案:

    #!/usr/bin/perl
    
    my $hivar = "this or that";
    
    while ($hivar =~ m/this|that/ig) {
            print "$&\n";
    }
    

    这是我遇到的一个现实世界问题的简化,虽然我从实践的角度对此感兴趣,但我也想知道幕后是什么触发了这种行为。这是一个似乎与谷歌不太兼容的问题。

    谢谢!

    汤姆

    1 回复  |  直到 14 年前
        1
  •  16
  •   hobbs    14 年前

    问题是有一个隐藏的值 每个字符串 不是 每一场比赛 控制一个 /g 匹配将继续,并可通过 pos($string) . 发生的是:

    1. pos($hivar) 是0, /this/ 在位置0处匹配并重置 POS($HIVAR) 到4。第二次匹配没有尝试,因为OR运算符已经是真的。 $& 变成“这个”并打印出来。
    2. POS($HIVAR) 是4, /这个/ 无法匹配,因为在4号或更高的位置没有“这个”。失败匹配重置 POS($HIVAR) 到0。
    3. /that/ 位置6和重置匹配 POS($HIVAR) 到10。 $& 变成“那个”然后打印出来。
    4. POS($HIVAR) 是10, /这个/ 无法匹配,因为在10号或更高的位置没有“这个”。失败匹配重置 POS($HIVAR) 到0。
    5. /那个/ 在位置6匹配并重置 POS($HIVAR) 到10。 $& 变成“那个”然后打印出来。

    步骤4和步骤5无限期重复。

    添加 c REGEX标志(它告诉引擎不要重置) pos 在匹配失败时)解决您提供的示例代码中的问题,但它可能是解决更复杂问题的理想解决方案,也可能不是。