【问题标题】:perl regex replace outside of string onlyperl 正则表达式仅替换字符串之外
【发布时间】:2020-05-20 21:32:22
【问题描述】:

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

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;

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

【问题讨论】:

  • 改为查看 Text::Balanced。
  • 你的预期输出是什么???

标签: regex perl


【解决方案1】:

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

我不确定以下是否漂亮,但这是我的方法:

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

如您所见,使用了“/e”修饰符。在这种情况下,删除 '"' 存储中的特殊项目 '"' 会很有帮助。

?&lt;str&gt; 捕获嵌入的字符串,假设内部没有嵌套的转义序列。我没有对它进行全面测试,但我认为这种方法与你的方法不等价,我也不知道它是否能正确处理所有边缘情况。

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

【讨论】:

    【解决方案2】:
    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 对我来说是缺失的部分。感谢您的回答。
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-21
      • 2010-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-13
      相关资源
      最近更新 更多