【问题标题】:In Perl, what is the meaning of if (s/^\+//)?在 Perl 中,if (s/^\+//) 是什么意思?
【发布时间】:2012-11-22 12:09:35
【问题描述】:

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

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

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

【问题讨论】:

  • @Oded,该链接不是我见过的最糟糕的 Perl 教程,但它相当陈旧并且使用了一些过时的做法(-wwarnings,原型)。我可能会推荐perldoc perlretut
  • @JoelBerger - 很公平。这是谷歌的第一次成功。
  • @Oded,NP。 Perl 教程的寿命是社区试图通过制作/突出更新更好的教程,并警告旧的/坏的教程perl-tutorial.org。 Perl 在 dot-com 繁荣带来了大量糟糕的代码后名声不佳,我们正试图一次一个教程让它变得更好。
  • 我已将该教程添加到perl-tutorial.org 上的旧教程列表中。它在一些旧语法上花费了太多时间,但它在接触新语法方面做得不错。这还不错,但对初学者来说不是最好的。
  • 你做了什么来尝试理解这段代码? Perl 附带的文档真的很全面。是什么阻止你在那里找到答案?

标签: regex perl perltk


【解决方案1】:

它们都是正则表达式。您可以在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
----------------------------------------------------------------------

更新:正如 cmets 中的 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
}

【讨论】:

  • 您的分析是准确的。我要补充一点,OP 应该考虑重构这段代码,以便替换更加明显。现在的写法很容易错过。即使只是去if( /^\+/ ) { $_ =~ s/^\+//; # do something } 也会有很大帮助。
  • @MikkoL 我同意并添加了建议。我不同意明确使用$_,但我相信这是个人偏好。谢谢。
  • 投反对票的人,你愿意评论我如何改进我的帖子吗?
  • 我不太喜欢这种重构。它添加了另一个模式匹配,并且在某些情况下模式匹配可能非常昂贵。使用if (s/.../.../) 来检查是否发生了替换也是一个非常正常的Perl 习惯用法。如果您担心清晰度,可以发表评论(注意:我不是反对者 - 总体而言答案很好)。
  • 我同意 dan,没有理由不 s/// 匹配和删除标记。这就是模式在标量上下文中返回匹配/替换数量的原因。
【解决方案2】:

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

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

s/^\+//

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

/^-/

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

【讨论】:

    【解决方案3】:

    这段代码相当于

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

    s///m// 是类似于正则表达式引号的运算符。您可以在perlop 中了解它们。

    【讨论】:

    • 这是一个非常好的(虽然很短)的答案。我不明白为什么它被否决了。
    • 我没有投反对票,但我确信这是因为,隐式变量在这里不是问题,而是替换模式本身。
    【解决方案4】:

    其他答案给出了代码如何工作的摘要,但没有给出太多原因。这是一个简单的例子,说明为什么人们可能会使用这种逻辑。

    #!/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 的示例涉及更多一点,但遵循相同的逻辑。

    • 如果密钥以+ 开头,请将其删除并执行一些操作
    • 如果密钥以- 开头,请不要删除它并执行其他操作

    【讨论】:

      猜你喜欢
      • 2018-05-02
      • 2011-09-27
      • 1970-01-01
      • 2018-03-05
      • 2010-12-28
      • 1970-01-01
      • 2023-03-25
      • 2022-06-10
      • 1970-01-01
      相关资源
      最近更新 更多