【问题标题】:Perl deferred interpolation of stringPerl延迟插值字符串
【发布时间】:2018-02-15 22:24:15
【问题描述】:

我有一种情况,其中有一个接收消息的分类脚本,将其与正则表达式列表进行比较,第一个匹配的设置存储桶。一些示例代码如下所示。

my $message = 'some message: I am bob';

my @buckets = (
    {
        regex => '^some message:(.*)',
        bucket => '"remote report: $1"',
    },
    # more pairs
);

foreach my $e (@buckets) {
    if ($message =~ /$e->{regex}/i) {
        print eval "$e->{bucket}";
    }
}

此代码将提供remote report: I am bob。我一直在看这个,觉得必须有更好的方法来做到这一点,然后它现在就完成了。特别是在存储桶中使用双引号 ('""')。有没有更好的处理方法?

【问题讨论】:

    标签: regex string perl eval pcre


    【解决方案1】:

    Perl 在计算该表达式时解析插值。为此,使用子程序就足够了,不需要eval

    ...
    bucket => sub { "remote report: $1" },
    ...
    print $e->{bucket}->();
    

    请注意,您还可以有效地评估您的正则表达式。您可以使用 qr// 运算符在哈希中使用预编译的正则表达式对象:

    ...
    regex => qr/^some message:(.*)/i,
    ...
    if ($message =~ /$e->{regex}/) {
    

    【讨论】:

    • 预编译正则表达式能给我什么?
    • @Prgrm.celeritas 主要价值是qr// 提供正确的引用,如果您在正则表达式中有任何反斜杠,这很重要。现在,您首先需要''-string 引用(这通常很简单),但字符串的结果将受到另一轮正则表达式转义处理。例如,正则表达式/\w+/ 必须写成'\\w+'。如果你真的从一个文件中加载这些正则表达式,那没关系。
    • 在正则表达式字符串中仅使用 \w+ 似乎没有问题。虽然添加选项的能力很好
    • 哦,你是对的!请注意,您还可以在模式中添加模式修饰符,例如 (?i:foo) – 就像 /foo/i
    【解决方案2】:

    你可以使用sprintf风格的格式字符串:

    use strict;
    use warnings;
    
    my $message = 'some message: I am bob';
    
    my @buckets = (
        {
            regex  => qr/^some message:(.*)/,
            bucket => 'remote report: %s',
        },
        # more pairs
    );
    
    foreach my $e (@buckets) {
        if (my @matches = ($message =~ /$e->{regex}/ig)) {
            printf($e->{bucket}, @matches);
        }
    }
    

    【讨论】:

    • 虽然这需要捕获组在位置上与说明符字符对齐正确吗?
    • @Prgrm.celeritas 是的,就像$1..$n 一样。不过,您实际上可以更改格式字符串中参数的顺序。有关详细信息,请参阅链接的文档。
    猜你喜欢
    • 1970-01-01
    • 2012-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多