【问题标题】:perl using constant in regexperl 在正则表达式中使用常量
【发布时间】:2017-02-09 14:05:20
【问题描述】:

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

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

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

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

我在网上查看,有人建议使用${\FOO}@{[FOO]} 有人提到(?{FOO})。我想知道是否有人可以阐明其中哪些是正确的,以及它们中的任何一个是否有任何优势。或者,只使用非常量变量会更好吗? (就我而言,性能是一个因素)。

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    在变量上使用常量的理由并不多。这并没有太大的区别——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 可以 em> 检测静态正则表达式,并自行检测。

        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;
    }
    

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

    【讨论】:

    • 我认为常量的意义不在于它们可能比变量快,而是它们是常量
    • 在我的特殊情况下,我使用的值确实是恒定的。出于这个原因,我正在考虑使用常量以及潜在的性能优势。
    • 也可以使用常量来组装几个使用通用组件的正则表达式。这可能会提高可维护性。
    【解决方案2】:

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

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

    current implemenationconstant pragma)中,它们是“inlinable 子程序”(参见)。

    使用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 是构建正则表达式模式的推荐方法。 (它是interpolates,除非分隔符是'。)性能提升通常很小,但你会得到一个适当的正则表达式,可以这样构建和使用(在这种情况下也是一个常量)。

    我很容易推荐Const::Fast 模块而不是另一个模块,实际上目前是所有其他模块。请参阅recent article,详细讨论两者。这是review 的许多其他选项。

    我强烈建议对只读的内容使用常量(您选择的类型)。这有利于代码的健康,以及与它接触的开发人员(包括众所周知的六个月内的开发人员)。


    这些是子例程,我们需要能够运行代码,以便对它们进行评估和替换为给定值。不能只是“插值”(评估)一个变量——它不是一个变量。

    run code inside a string(需要interpolated,因此有效地双引号)的一种方法是取消引用,其中引用下的块中有一个表达式;然后计算表达式。所以我们需要先做这个参考。所以要么

    say "@{ [FOO] }";  # make array reference, then dereference
    

    say "${ \FOO }";   # make scalar reference then dereference
    

    打印foo。请参阅文档以了解其工作原理和示例。因此,人们可以在正则表达式中做同样的事情,无论是在匹配部分还是替换部分中

    s/prefix1_${\FOO}/prefix2_${\BAR}/g;
    

    (或@{[...]}),因为它们被评估为插值字符串。

    哪个“更好”?这些都是技巧。很少(如果有的话)需要这样做。它有很好的机会迷惑读者。所以我根本不建议使用这些。

    至于(?{ code }),这是一个正则表达式功能,代码在模式内进行评估(仅匹配端)。它既复杂又棘手,而且很少需要。请参阅 in perlretutin perlre

    讨论这些事情的速度并不重要。它们肯定超出了干净和惯用代码的范围,而您很难检测到运行时差异。

    但如果您必须使用其中之一,我宁愿通过技巧在标量引用中进行插值,然后使用复杂的正则表达式功能。

    【讨论】:

    • 不应该 qr/foo/iqr/$foo/i
    • @U.Windl 事实上,它是一个更好的例子,使用变量,改变了评论。谢谢
    【解决方案3】:

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

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

    这是whole discussion的链接。

    【讨论】:

    • 我想知道:这是否回答了这个问题(${\FOO} vs. @{[FOO]} vs. (?{FOO}))?
    • 这正是我想要的。谢谢!
    【解决方案4】:
    use constant FOO => "foo";
    use constant BAR => "bar";
    
    my $var =~ s/prefix1_${\FOO}/prefix2_${\BAR}/g;
    

    信用:https://www.perlmonks.org/?node_id=293323

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-08
      • 1970-01-01
      • 2014-01-06
      • 2012-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多