【问题标题】:Perl: test regex without creating new variablePerl:在不创建新变量的情况下测试正则表达式
【发布时间】:2018-10-21 21:53:30
【问题描述】:

对不起,如果这是一个基本问题,但我对 perl 有点陌生,我觉得应该有办法做到这一点,但找不到任何文档。我想知道您是否可以在没有丢弃变量$doto 的情况下执行以下操作:

my $file="foo/bar.c";
my $doto = $file;
$doto =~ s/\.c$/\.o/;
print ".o exists" if ( -f $doto );

也就是说,类似于:

print ".o exists" if ( -f ($file =~ s/\.c$/\.o/gr) );

(但这当然会产生编译错误)。

我的编译错误如下:

在第 2 行,“s/.c$/.o/gr”附近的操作员预期的位置找到了裸字

这是perl, v5.8.9

【问题讨论】:

  • edit您的问题并告诉我们编译错误。当我适应并在 5.26 上尝试时,您的代码对我有用。 $ perl -E 'my $file = "foo.c"; say ".o exists" if -f $file =~ s/\.c$/\.o/gr;' 编译,不打印任何内容。 touch foo.c foo.o && perl -E 'my $file = "foo.c"; say ".o exists" if( -f ($file =~ s/\.c$/\.o/gr));' 打印一个空行和.o exists。带括号和不带括号。
  • @GerhardBarnard:在此示例中,我想根据 .c 文件的名称来测试 .o 文件是否存在。但这更多是关于如何用更少的变量编写更易维护的代码。
  • @simbabque: 嗯,它不适用于 perl 5.8(实际上我的 perl 不喜欢 -E 选项...),但如果我使用带有剪切和粘贴的标准输入你的代码,它抱怨。所以这只是一个版本的事情。我可以用额外的变量来做到这一点,我只是想练习编写更整洁的代码......
  • 5.8 没有用于替换的 /r 标志。这是在 5.14 中添加的。见perldoc.perl.org/…
  • 注意/g修饰符在这里没有意义,应该省略。

标签: perl


【解决方案1】:

你的陈述

print ".o exists" if ( -f ($file =~ s/\.c$/\.o/gr) )

在支持/r 修饰符的 Perl 版本(v5.14 或更高版本)上运行良好。 (注意/g是多余的。)

没有它,就无法在不修改变量的情况下应用替换,尽管您可以使用块使其成为非常短暂的临时变量

{
    (my $doto = $file) =~ s/\.c$/\.o/;
    print ".o exists" if -f $doto;
}

【讨论】:

  • @Gerhard:给定一个文件名*.c,他们想发现对应的*.o是否存在。如果你喜欢的话,就像一个 make 文件。
【解决方案2】:

这个答案谈到使实际的print if -f 查找代码更具可读性。如果你想让代码运行得更快,这个方案比你的方案要贵。

由于在您的 Perl 版本中没有非破坏性替代,您所能做的就是为此实现您自己的函数。它不会像s///r 那样好,但它可以胜任。如果您多次出现这种类型的代码,那将是有意义的。

sub replace {
    my ($text, $pattern, $replacement) = @_;

    $text =~ s{$pattern}{$replacement}g; # do you need /g?
    return $text;
}

# ... later

print ".o exists" if -f replace($file, qr/\.c$/, '.o');

这已经为您制作了一份副本,就像您的临时变量一样,所以 $file 实际上不会被更改。

请注意,您的 /g 是无用的,因为文件名只会有一行的结尾,但以后可能不会没用。但是,最好不要在那里修复它,而是传入一个可选标志作为另一个参数。

replace( $file, qr/.../, '.o', 'g' ); # where 'g' just means any true value

sub replace {
    my ($text, $pattern, $replacement, $global) = @_;

    if ($global) {
         $text =~ s{$pattern}{$replacement}g;
    } else {
         $text =~ s{$pattern}{$replacement};
    }

    return $text;
}

您通常也不需要转义替换部分中的.,因为这实际上不是正则表达式模式,只是一个字符串。

【讨论】:

  • 这让我想起了很多php.net/manual/en/function.preg-replace.php,但不知何故,我的实现中的参数顺序更像 Perlish。
  • 这里仍然使用临时变量$text;实际上它使用了三个!
  • @Borodin 确实如此。但它是更简洁的代码。我认为这才是重点,而不是优化性能。
  • 如果想法是收紧代码,那么可以使用 (my $doto = $file) =~ s/\.c$/\.o/ 将 OP 的版本减少到几行
  • 还不如使用 String::Substitution gsub_copy/gsub_modify 来代替。除了节省代码之外,它还支持$1等替换表达式!
【解决方案3】:

我会通过添加如下函数来处理它。

sub doto_exists {
    my $doto = shift;
    $doto =~ s/\.c$/\.o/;
    return (-f $doto);
}

$file = "file1.c";

print ".o exists\n" if doto_exists($file) ;

【讨论】:

  • 请注意,现代 Perl 的最佳实践建议使用 snake_case 函数名称。虽然我们喜欢骆驼,但我们不喜欢 CamelCase。 ;)
  • @simbabque:我已经调整了答案以反映snake_case。我看到一些关于 perl 的蛇案例与骆驼案例主题的讨论。你能引用一个参考链接吗?
猜你喜欢
  • 2011-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-13
  • 2016-01-21
  • 2022-06-15
  • 1970-01-01
  • 2021-07-30
相关资源
最近更新 更多