【问题标题】:perl regex for variable substitution用于变量替换的 perl 正则表达式
【发布时间】:2018-04-25 12:28:19
【问题描述】:

我想替换用“#”标记并以点或非字母数字字符结尾的变量。 示例:变量#name 应替换为“Peter”

abc#name.def => abcPeterdef abc#namedef => abc#namedef abc#name-def => abcPeter-def

因此,如果变量以点结尾,则会将其替换并删除点。它是否被任何非字母字符终止,它也被替换。

我使用以下:

s/#name\./Peter/i
s/#name(\W)/Peter$1/i

这可行,但是否可以将其合并到一个表达式中?

【问题讨论】:

  • 如果你真的在做 Perl 变量替换,那么你可能想看看String::Interpolate,它使 perl 自己的运行时双引号字符串插值代码可用。这样您就可以使用$s = 'abc$name-def'$s = 'abc${name}def',然后在设置$name = 'Peter' 后进行插值。

标签: regex perl


【解决方案1】:

有几种可能的方法。

s/#name(\W)/"Peter" . ($1 eq "." ? "" : $1)/e

这里我们使用/e将替换部分转换为表达式,因此我们可以检查$1并动态选择替换字符串。

s/#name(?|\.()|([^.\w]))/Peter$1/

这里我们使用(?|)来重置分支之间捕获组的编号,所以\.()([^.\w])都设置了$1。如果匹配了.,则$1 变为空字符串;否则它包含匹配的字符。

【讨论】:

  • 将使用一系列匹配项中的第一个,所以(?|\.()|(\W)) 很好。
  • @Borodin 是的,但我觉得[^.\w] 更加明确和强大。例如。如果有人将它嵌入到更大的上下文中,我的正则表达式就不会以意想不到的方式开始匹配。
【解决方案2】:

你可以使用

s/#name(?|\.()|(\W))/Peter$1/i

详情

  • #name - 匹配文字子串
  • (?|\.()|(\W)) - 一个 branch reset group 匹配以下两种选择之一:
    • \.() - 一个点,然后将一个空字符串捕获到$1
    • | - 或
    • (\W) - 捕获到 $1 中的任何非单词字符。

因此,在匹配时,$1 占位符要么为空,要么包含除点之外的任何非单词字符。

【讨论】:

  • @melpomene 我们可以使用s/#name(?|\.()|(\W))/Peter$1/i解决它
【解决方案3】:

您可以通过使用文字点或单词边界作为终止符来做到这一点

这样

s/#name(?:\.|\b)/Peter/i

这是一个完整的程序,可以重现您的问题中显示的所需输出

use strict;
use warnings 'all';

for my $s ( 'abc#name.def', 'abc#namedef', 'abc#name-def' ) {

    ( my $s2 = $s ) =~ s/#name(?:\.|\b)/Peter/i;

    printf "%-12s => %-s\n", $s, $s2;
}

输出

abc#name.def => abcPeterdef
abc#namedef  => abc#namedef
abc#name-def => abcPeter-def

【讨论】:

  • 哦,整洁。你甚至可以做#name\b\.?
  • @melpomene:我没有发现。我一直在从#name(?:\.|(?=\W)) 向后工作,但只完成了一半!
  • @Melpomene: s/#name\b\.?/Peter/ 不错!
猜你喜欢
  • 2017-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-19
  • 2015-02-11
  • 1970-01-01
相关资源
最近更新 更多