在一根弦上执行两个(冲突)插值



我有一个插值函数,它将%foo替换为 $HV{'default'}{'foo'} 中的值和 $HV{foo}{bar} 中的%foo.bar值:

sub interpolate {
    my $work = "@_";
    $work =~ s/%(w+).(w+)/$HV{$1}{$2}/g;
    $work =~ s/%(w+)/$HV{'default'}{$1}/g;
    return $work;
}

但是,如果$HV{'foo'}{'bar'}包含%字符,则第二个操作会匹配它,这不是我想要的。 我的第一个解决方法是将所有出现的%foo更改为 %default.foo

$work =~ s/%(w+)/%default.$1/g;
$work =~ s/%(w+).(w+)/$HV{$1}{$2}/g;

但这%foo.bar变成了%default.foo.bar. 有没有办法在不重新做哈希的情况下做我想做的事?

同样对于奖金积分,我对一个正则表达式感兴趣,该表达式会将%A.very.long.and.deeply.nested.hash.value与相应的值匹配以使其适用于任何哈希。

最简单的解决方案是执行字符串的单遍历,而不是连续遍历两次:

$work =~ s{%(w+)(?:.(w+))?}{
    defined $2
        ? $HV{$1}{$2}
        : $HV{default}{$1}
}eg;

要修复您的其他方法,您可以将正则表达式更改为

$work =~ s/%(w+)(?!.w)/%default.$1/g;

仅当%foo后面没有.bar时才替换它。


奖励积分:假设您想用 $HV{foo}{bar}{baz} 替换%foo.bar.baz,这可以按如下方式完成:

sub lookup {
    my ($cur, @keys) = @_;
    $cur = $cur->{$_} for @keys;
    return $cur;
}
s{%(w+(?:.w+)*)}{
    lookup(%HV, split(/./, $1))
}eg;

最新更新