2

在 Perl/Tk 代码中,我发现了如下条件语句

if (s/^\+//)
{
   #do something
}
elsif (/^-/)
{
   #do another thing
}

似乎已经完成了一些模式匹配。但我无法理解。谁能帮我理解这种模式匹配?

4

4 回答 4

12

它们都是正则表达式。您可以在perlreperlretut阅读它们。您可以在http://www.rubular.com上玩弄它们。

他们都隐含地用$_. 您的代码行中可能有一个whileforeach周围没有循环变量。在这种情况下,$_成为那个循环变量。例如,它可能包含正在读取的文件的当前行。

  1. 如果 的当前值$_包含一个+(加号)作为字符串开头的第一个字符,则#do somehting.
  2. 否则,如果它包含一个-(减号)符号,#do another thing.

在案例 1 中,它也会用+任何内容替换该符号(即删除它)。它不会删除-2. 但是。


让我们看一下YAPE::Regex::Explain的解释。

use YAPE::Regex::Explain;
print YAPE::Regex::Explain->new(qr/^\+/)->explain();

这里是。在我们的案例中并没有真正的帮助,但仍然是一个不错的工具。请注意,(?-imsx)部分是 Perl 所暗示的默认内容。除非您更改它们,否则它们始终存在。

The regular expression:

(?-imsx:^\+)

matches as follows:

NODE                     EXPLANATION
----------------------------------------------------------------------
(?-imsx:                 group, but do not capture (case-sensitive)
                         (with ^ and $ matching normally) (with . not
                         matching \n) (matching whitespace and #
                         normally):
----------------------------------------------------------------------
  ^                        the beginning of the string
----------------------------------------------------------------------
  \+                       '+'
----------------------------------------------------------------------
)                        end of grouping
----------------------------------------------------------------------

更新:正如 Mikko L 在评论中指出的那样,您也许应该重构/更改这段代码。虽然它可能会做它应该做的事情,但我相信让它更具可读性是一个好主意。写它的人显然并不关心你作为后来的维护者。我建议你这样做。您可以将其更改为:

# look at the content of $_ (current line?)
if ( s/^\+// )
{
  # the line starts with a + sign,
  # which we remove!

  #do something
}
elsif ( m/^-/ )
{
  # the line starts witha - sign
  # we do NOT remove the - sign!

   #do another thing
}
于 2012-11-22T12:16:28.077 回答
5

这些是正则表达式,用于模式匹配和替换。

你应该阅读这个概念,但至于你的问题:

s/^\+//

如果字符串以加号开头,则删除该加号(“s”表示“替换”),并返回 true。

/^-/

如果字符串以减号开头,则为真。

于 2012-11-22T12:16:34.550 回答
3

这段代码相当于

if ($_ =~ s/^\+//) {  # s/// modifies $_ by default
   #do something
}
elsif ($_ =~ m/^-/) {  # m// searches $_ by default
   #do another thing
}

s///并且m//是 regexp 类似引号的运算符。您可以在perlop中了解它们。

于 2012-11-22T12:18:48.057 回答
2

其他答案总结了代码的工作原理,但并没有说明原因。这是一个简单的例子,说明为什么人们可能会使用这种逻辑。

#!/usr/bin/env perl

use strict;
use warnings;

my $args = {};

for ( @ARGV ) {
  if ( s/^no// ) {
    $args->{$_} = 0;
  } else {
    $args->{$_} = 1;
  }
}

use Data::Dumper;
print Dumper $args;

当你调用脚本时

./test.pl hi nobye

你得到

$VAR1 = {
          'hi' => 1,
          'bye' => 0
        };

键是字符串,但是如果它在前面,no则将其删除(以获取有问题的键)并将值设置为0.

OP 的示例涉及更多一点,但遵循相同的逻辑。

  • 如果密钥以 a 开头+,请将其删除并执行某些操作
  • 如果密钥以 a 开头-,请不要删除它并执行其他操作
于 2012-11-22T15:34:32.933 回答