perl在正则表达式中使用常量

时间:2017-02-09 14:05:20

标签: regex perl

我想知道在perl正则表达式中使用常量。我想做类似的事情:

use constant FOO => "foo"
use constant BAR => "bar"

$somvar =~ s/prefix1_FOO/prefix2_BAR/g;

当然,在那里,FOO解析为三个字母F O O,而不是扩展为常量。

我在线观看,有人建议使用${\FOO}@{[FOO]}其他人提及(?{FOO})。我想知道是否有人可以了解哪些是正确的,以及是否有任何优势。或者,使用非常量变量更好吗? (性能是我的一个因素)。

3 个答案:

答案 0 :(得分:6)

在变量上使用常量的原因并不多。它没有太大的区别 - 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
   }
);

给出:

          Rate const   var
const 917095/s    --   -1%
var   923702/s    1%    --

真的不够担心。

然而,值得注意的是 - 您可以使用qr//编译正则表达式并按照这种方式执行,只要RE是静态的 - 可能会提高性能(但它可能不会,因为perl 可以检测静态正则表达式,并自行完成。

    Rate      var    const compiled
var      910498/s       --      -2%      -9%
const    933097/s       2%       --      -7%
compiled 998502/s      10%       7%       --

代码如下:

my $compiled_regex = qr/prefix1_$FOO_VAR/;
sub compiled_regex { 
    my $somvar = "prefix1_foo test";
    $somvar =~ s/$compiled_regex/prefix2_$BAR_VAR/g;
}

老实说 - 这是微观优化。与您的代码相比,正则表达式引擎很快,所以不要担心它。如果性能对您的代码至关重要,那么处理它的正确方法是首先编写代码,然后对其进行分析以寻找要优化的热点。

答案 1 :(得分:4)

您显示的问题是由于这些常量是裸字(在编译时构建)

  

使用此模块定义的常量不能插入到变量等字符串中。

在“当前实施”(v5.24 docs)中,它们是无法使用的子程序。请参阅constant pragma。

使用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;

现在他们将被插值。请注意,更复杂的替换可能需要/e

这些是在运行时构建的,因此您可以将表达式的结果分配给它们。特别是,您可以使用qr operator,例如

const my $patt => qr/foo/i;  # case-insensitive 

qr是构建正则表达式模式的推荐方法。性能增益通常很小,但是你得到一个常量,这是一个正确的正则表达式(并且可以这样构建)。

我使用这个模块并没有遇到任何问题。我很乐意推荐它。请参阅recent article并详细讨论两者。这是许多其他选项的review

答案 2 :(得分:1)

根据PerlMonk的说法,如果您担心性能,最好创建一个已插入的字符串:

use constant PATTERN => 'def';
my $regex = qr/${\(PATTERN)}/; #options such as /m can go here.
if ($string =~ regex) { ... }

以下是whole discussion的链接。