清除正则表达式匹配变量的最佳方法是什么?

时间:2012-04-18 20:35:10

标签: regex perl backreference

清除/重置所有正则表达式匹配变量的最佳方法是什么?

  • 示例如何在正则表达式操作之间重置$1并使用最近的匹配:

    $_="this is the man that made the new year rumble"; 
    / (is) /; 
    / (isnt) /; 
    say $1;          # outputs "is"
    
  • 示例在使用循环时这可能会出现问题:

    foreach (...){
       /($some_value)/;
       &doSomething($1) if $1;
    }
    

更新:我认为我不需要这样做,但是示例2只是一个例子。这个问题是关于重置匹配变量,而不是实现它们的最佳方式。

无论如何,最初我的编码风格更明确并且使用if-blocks。现在回到这个(例2)之后,阅读许多行代码会更加简洁,我会发现这种语法更快理解。

6 个答案:

答案 0 :(得分:18)

您应该使用匹配的回报,而不是组变量的状态。

foreach (...) {
    doSomething($1) if /($some_value)/;
}
如果匹配成功,

$ 1等仅保证反映最近的匹配。除了比赛成功后,你不应该看着他们。

答案 1 :(得分:14)

正则表达式捕获*由成功匹配重置。要重置正则表达式捕获,可以使用保证匹配的普通匹配操作。

"a" =~ /a/;  # Reset captures to undef.

是的,它看起来很奇怪,但你要求做一些奇怪的事情。

如果您修复您的代码,则不需要看起来很奇怪的解决方法。修复代码甚至会发现错误!

修正:

$_ = "this is the man that made the new year rumble"; 
if (/ (is) / || / (isnt) /) {
   say $1; 
} else{ 
   ...  # You're currently printing something random.
}

for (...) {
   if (/($some_pattern)/) {
      do_something($1);
   }
}

* - Backrefs是与之前捕获的文本匹配的正则表达式模式。例如\1\k<foo>。你实际上是在谈论“正则表达式捕获缓冲区”。

答案 2 :(得分:5)

您应该测试匹配是否成功。例如:

foreach (...){
   /($some_value)/ or next;
   doSomething($1) if $1;
}

foreach (...){
   doSomething($1) if /($some_value)/ and $1;
}

foreach (...){
   if (/($some_value)/) {
      doSomething($1) if $1;
   }
}

根据$some_value是什么,以及您希望如何处理匹配空字符串和/或0,您可能需要或可能不需要测试$1

答案 3 :(得分:1)

你应该这样做:

foreach (...) { 
   someFnc($1) if /.../; 
}

但如果你想坚持自己的风格,那么请将其作为一个想法:

$_ = "this is the man that made the new year rumble";  

$m = /(is)/   ? $1 : undef;
$m = /(isnt)/ ? $1 : undef;

print $m, "\n" if defined $m;

答案 4 :(得分:1)

补充现有的,有用的答案(以及通常在布尔上下文中测试匹配操作结果的明智建议,并且只有在测试成功的情况下才采取行动):

根据您的情况,您可以采用不同的方式解决问题:

免责声明:我不是一位经验丰富的Perl程序员;如果这种方法存在问题,请告诉我。

将匹配操作包含在do { ... }块范围内,将所有与正则表达式相关的特殊变量($&$1,...)纳入该块

因此,你可以使用do { ... }来防止这些特殊变量首先被设置(尽管来自块之外的先前正则表达式操作的那些显然仍然有效);例如:

$_="this is the man that made the new year rumble"; 

# Match in current scope; -> $&, $1, ... *are* set.
/ (is) /;

# Match inside a `do` block; the *new* $&, $1, ... values
# are set only *inside* the block; 
# `&& $1` passes out the block's version of `$1`.
$do1 = do { / (made) / && $1 };

print "\$1 == '$1'; \$do1 == '$do1'\n";  # -> $1 == 'is'; $do1 == 'made'
  • 这种方法的优点是当前范围的 none 设置或改变了特殊的正则表达式变量;相反,接受的答案会改变$&$'等变量。
  • 缺点是您必须明确传出感兴趣的变量;但是,默认情况下会得到匹配操作的结果,如果您只对捕获缓冲区的内容感兴趣,那就足够了。

答案 5 :(得分:0)

将捕获物分配给列表的行为更接近您想要的声音。

for ("match", "fail") {
    my ($fake_1) = /(m.+)/;
    doSomething($fake_1) if $fake_1;
}