Perl 正则表达式仅替换字符串外部



我有字符串,我需要在其中找到变量才能用值替换它们。例如:

my $str = "var1 var2 blah blah blah var3"

有时字符串具有嵌入的字符串:

my $str = "var1 var2 blah "do not replace this: var1" blah blah var3"

所以我构建了一个匹配字符串和变量的正则表达式。当它匹配字符串时,它会将其替换为自身。当它匹配变量时,它会用哈希结果替换它们。为了使它以正则表达式形式工作,我将捕获分为两部分,命名组(宏(和最后一个匹配项。对于字符串,我将第一个引号字符 ("( 捕获到命名组中,将字符串的其余部分捕获到最后一个匹配项中。对于变量,我在命名组中捕获整个变量,而在最后一个捕获组中不捕获任何内容。为了处理字符串,我为 {"} = '"' 添加一个哈希条目。对于每个匹配项,我粘贴哈希查找,然后粘贴最后一个匹配项。这表现令人钦佩 - 尽管看起来很尴尬。

$line =~ s/(?:(?<macro>(?<!\)")(.*?(?<!\)")|(?<macro>(``|b($list_of_hash_keys)b))())/$variables->{$+{macro}}$+/gs;

在漂亮的正则表达式形式中是否有更清洁的方式?

看来您正在尝试实现一个迷你模板机制。 :)

我不确定以下内容是否美丽,但这是我的方法:

my $out = $str =~ s{
(?<str> " [^"]+ " ) |
(?<macro> b $list_of_hash_keys b)
}{
$+{str} // $variables->{$+{macro}}
}gsxre;

如您所见,使用了"/e"修饰符。在这种情况下,摆脱$variable藏匿处中'"'的特殊物品很有帮助。

?<str>捕获嵌入的字符串,假设内部没有嵌套的转义序列。我没有完全测试它,但我认为这种方法与您的方法并不等同,我也不知道它是否正确处理了所有边缘情况。

但我认为这应该足以证明这个想法。

use Modern::Perl;
my @in = (
"var1 var2 blah blah blah var3",
"var1 var2 blah "do not replace this: var1" blah blah var3",
);
my $variables = {
var1 => "mod1",
var2 => "mod2",
var3 => "mod3",
var4 => "mod4",
};
my $list_of_hash_keys = 'b(' . join('|',keys(%$variables)) . ')b';
for (@in) {
s/"[^"]+"(*SKIP)(*FAIL)|$list_of_hash_keys/$variables->{$1}/g;
say
}

输出:

mod1 mod2 blah blah blah mod3
mod1 mod2 blah "do not replace this: var1" blah blah mod3

解释:

"                       # quote
[^"]+                   # 1 or more non quote
"                       # quote
(*SKIP)                 # skip everything that's been matching (i.e. everything between quotes)
(*FAIL)                 # fail the match
|                       # OR
$list_of_hash_keys      # list of keys to match, captured in group 1

答案是(*SKIP((*FAIL(。我需要做的是匹配字符串,后跟(*SKIP((*FAIL(,这将处理它。

最新更新