我能否从一组哈希键构建Perl正则表达式?

4

(与之前的问题相关:我需要重置Perl哈希索引吗?)

我从一个文件中获取了一个哈希,其定义如下:

%project_keys = (
    cd     => "continuous_delivery",
    cm     => "customer_management",
    dem    => "demand",
    dis    => "dis",
    do     => "devops",
    sel    => "selection",
    seo    => "seo"
);

我需要检查评论标题是否有正确的格式,如果是,就链接到一个单独的URL。

例如,如果评论标题是

"cm1234 - Do some CM work"

我想链接到以下URL:

http://projects/customer_management/setter/1234

目前,我正在使用以下(硬编码)正则表达式:

if ($title =~ /(cd|cm|dem|dis|do|sel|seo)(\d+)\s.*/) {
    my $url = 'http://projects/'.$project_keys{$1}.'/setter/'.$2
}

但是显然我想从哈希键本身构建正则表达式(上面的哈希示例会相对频繁地更改)。 我考虑简单地将键朴素地连接如下:

# Build the regex
my $regex = '';
foreach my $key ( keys %project_keys ) {
    $regex += $key + '|';
}
$regex = substr($regex, 0, -1); # Chop off the last pipe
$regex = '('.$regex.')(\d+)\s.*';
if ($title =~ /$regex/) {
    my $url = 'http://projects/'.$project_keys{$1}.'/setter/'.$2
}

但是,a) 它没有按照我的期望工作,b) 我认为有更好的 Perl 方法来完成这个任务。或者还有其他方法吗?

1个回答

6
你的主要问题出在尝试使用+连接字符串上。在Perl中,它并不起到这个作用,字符串连接操作符是.。但是,使用join代替字符串连接循环通常会更好。
我建议:
my $project_match = join '|', map quotemeta, keys %project_keys;

if ($title =~ /($project_match)(\d+)\s/) {
   my $url = 'http://projects/'.$project_keys{$1}.'/setter/'.$2;
   # Something with $url
}

quotemeta 是一个函数,用于转义字符串中出现的任何正则表达式元字符。虽然在您的示例中没有这样的字符,但通常最好始终使用它以避免意外错误。

我在您的模式中省略了尾随的 .*,因为如果您不对这些内容进行任何操作,那么没有必要说“然后一些东西,或者可能没有东西”。除非将模式锚定到字符串的开头和结尾,否则模式不需要匹配整个字符串。


太棒了。真是太棒了。 - roryhewitt
如果我正确阅读了文档,那么在正则表达式中不加括号的情况下它也可以工作 - 我想知道是否加括号是为了在后续字符串中使用$1? - roryhewitt
@roryhewitt 不,如果没有第一组括号,那么$1将是ID,而$2则不会被设置。 - hobbs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接