我有一个插值函数,它将%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;