我想知道在perl正则表达式中使用常量.我想做类似的事情:
use constant FOO => "foo"
use constant BAR => "bar"
$somvar =~ s/prefix1_FOO/prefix2_BAR/g;
Run Code Online (Sandbox Code Playgroud)
当然,在那里,FOO解决了三个字母F O O而不是扩展到常数.
我在线查看,有人建议使用其中任何一个${\FOO}或@{[FOO]}其他人提到的(?{FOO}).我想知道是否有人可以了解哪些是正确的,以及是否有任何优势.或者,使用非常量变量更好吗?(性能是我的一个因素).
在变量上使用常量的原因并不多.它没有太大的区别 - perl无论如何都会编译一个正则表达式.
例如:
#!/usr/bin/perl
use warnings;
use strict;
use Benchmark qw(:all);
use constant FOO => "foo";
use constant BAR => "bar";
my $FOO_VAR = 'foo';
my $BAR_VAR = 'bar';
sub pattern_replace_const {
my $somvar = "prefix1_foo test";
$somvar =~ s/prefix1_${\FOO}/prefix2_${\BAR}/g;
}
sub pattern_replace_var {
my $somvar = "prefix1_foo test";
$somvar =~ s/prefix1_$FOO_VAR/prefix2_$BAR_VAR/g;
}
cmpthese(
1_000_000,
{ 'const' => \&pattern_replace_const,
'var' => \&pattern_replace_var
}
);
Run Code Online (Sandbox Code Playgroud)
得到:
Rate const var
const 917095/s -- -1%
var 923702/s 1% --
Run Code Online (Sandbox Code Playgroud)
真的不够担心.
然而,值得注意的是 - 您可以编译正则表达式并以qr//这种方式执行,如果RE是静态的 - 可能会提高性能(但它可能不会,因为perl 可以检测静态正则表达式,并且自己这样做.
Rate var const compiled
var 910498/s -- -2% -9%
const 933097/s 2% -- -7%
compiled 998502/s 10% 7% --
Run Code Online (Sandbox Code Playgroud)
使用以下代码:
my $compiled_regex = qr/prefix1_$FOO_VAR/;
sub compiled_regex {
my $somvar = "prefix1_foo test";
$somvar =~ s/$compiled_regex/prefix2_$BAR_VAR/g;
}
Run Code Online (Sandbox Code Playgroud)
老实说 - 这是微观优化.与您的代码相比,正则表达式引擎很快,所以不要担心它.如果性能对您的代码至关重要,那么处理它的正确方法是首先编写代码,然后对其进行分析以寻找要优化的热点.
显示的问题是由于这些常量是裸词(在编译时构建)
使用此模块定义的常量不能像变量一样插入到字符串中。
在当前的实现(constantpragma)中,它们是“可内联的子程序”(参见†)。
使用像Const::Fast这样的模块可以很好地解决这个问题
use Const::Fast;
const my $foo => 'FOO';
const my $bar => 'BAR';
my $var = 'prefix1_FOO_more';
$var =~ s/prefix1_$foo/prefix2_$bar/g;
Run Code Online (Sandbox Code Playgroud)
现在他们确实得到了插值。请注意,可能需要更复杂的替换/e。
这些是在运行时构建的,因此您可以将表达式的结果分配给它们。特别是,您可以使用qr 运算符,例如
const my $patt => qr/$foo/i; # case-insensitive
Run Code Online (Sandbox Code Playgroud)
这qr是构建正则表达式模式的推荐方法。(除非分隔符是 ,否则它会进行插值'。)性能增益通常很小,但您会得到一个合适的正则表达式,可以这样构建和使用(在这种情况下也是一个常量)。
我Const::Fast很容易推荐模块而不是另一个,事实上在这个时候超过所有其他模块。请参阅最近的一篇文章,其中对两者进行了详细讨论。这是对许多其他选项的回顾。
我强烈建议对只读的事物使用常量(您选择的类型)。这对代码的健康以及接触它的开发人员(包括众所周知的六个月内的您自己)的健康都有好处。
†这些是子例程,我们需要能够运行代码以便评估它们并用给定值替换它们。不能只是“插入”(评估)一个变量——它不是一个变量。
在字符串中运行代码的一种方法(需要插值,因此有效地双引号)是取消引用,其中引用下的块中有一个表达式;然后计算表达式。所以我们需要先做那个参考。所以要么
say "@{ [FOO] }"; # make array reference, then dereference
Run Code Online (Sandbox Code Playgroud)
或者
say "${ \FOO }"; # make scalar reference then dereference
Run Code Online (Sandbox Code Playgroud)
打印foo。请参阅文档以了解其工作原理和示例。因此,您可以在正则表达式中执行相同的操作,并且可以在匹配和替换部分中执行相同的操作
s/prefix1_${\FOO}/prefix2_${\BAR}/g;
Run Code Online (Sandbox Code Playgroud)
(或与@{[...]}),因为它们被评估为内插字符串。
哪个更好”?这些都是技巧。很少(如果有的话)需要这样做。它有很好的机会迷惑读者。所以我根本不建议诉诸这些。
至于(?{ code }),这是一个正则表达式功能,其中代码在模式内进行评估(仅匹配侧)。它既复杂又棘手,而且很少需要。在 perlretut和perlre 中查看它。
讨论这些事情的速度并不重要。它们肯定超出了干净和惯用代码的范围,而您很难检测到运行时差异。
但是,如果您必须使用其中之一,我宁愿通过技巧在标量引用中进行插值,然后再使用复杂的正则表达式功能。