我想在正则表达式中使用字符串变量进行搜索模式和替换。预期的输出是这样的,
$ perl -e '$a="abcdeabCde"; $a=~s/b(.)d/_$1$1_/g; print "$a\n"'
a_cc_ea_CC_e
但是当我将模式和替换移动到变量时,$1
未被评估。
$ perl -e '$a="abcdeabCde"; $p="b(.)d"; $r="_\$1\$1_"; $a=~s/$p/$r/g; print "$a\n"'
a_$1$1_ea_$1$1_e
当我使用“ee”修饰符时,它会出错。
$ perl -e '$a="abcdeabCde"; $p="b(.)d"; $r="_\$1\$1_"; $a=~s/$p/$r/gee; print "$a\n"'
Scalar found where operator expected at (eval 1) line 1, near "$1$1"
(Missing operator before $1?)
Bareword found where operator expected at (eval 1) line 1, near "$1_"
(Missing operator before _?)
Scalar found where operator expected at (eval 2) line 1, near "$1$1"
(Missing operator before $1?)
Bareword found where operator expected at (eval 2) line 1, near "$1_"
(Missing operator before _?)
aeae
我在这里想念什么?
$p
和$r
都是我自己写的。我需要的是在不触及perl代码的情况下进行多个类似的正则表达式替换,因此$p
和$r
必须位于单独的数据文件中。我希望以后可以将此文件与C ++ / python代码一起使用。
以下是$p
和$r
的一些示例。
^(.*\D)?((19|18|20)\d\d)年 $1$2<digits>年
^(.*\D)?(0\d)年 $1$2<digits>年
([TKZGD])(\d+)/(\d+)([^\d/]) $1$2<digits>$3<digits>$4
([^/TKZGD\d])(\d+)/(\d+)([^/\d]) $1$3分之$2$4
答案 0 :(得分:10)
使用$p="b(.)d";
,您将获得一个包含文字字符b(.)d
的字符串。通常,正则表达式模式不会保留在带引号的字符串中,并且可能在正则表达式中没有它们的预期含义。但是,请在最后看到注意。
这是qr operator的用途:$p = qr/b(.)d/;
将字符串形成为正则表达式。
对于替换部分和/ee
,问题是首先评估$r
,以产生_$1$1_
,然后将其作为代码进行评估。唉,这不是有效的Perl代码。 _
是裸字,即使$1$1
本身无效(例如,$1 . $1
也是如此。
$r
提供的示例$N
以各种方式混合了文字。解析此问题的一种方法是将所有$N
和所有其他内容提取到一个列表中,该列表从字符串维护其顺序。然后,可以将其处理为将成为有效代码的字符串。例如,我们需要
'$1_$2$3other' --> $1 . '_' . $2 . $3 . 'other'
这是可以评估的有效Perl代码。
split在分隔符模式中捕获,有助于解决这个问题。
sub repl {
my ($r) = @_;
my @terms = grep { $_ } split /(\$\d)/, $r;
return join '.', map { /^\$/ ? $_ : q(') . $_ . q(') } @terms;
}
$var =~ s/$p/repl($r)/gee;
在/(...)/
的模式中捕获split
时,分隔符将作为列表的一部分返回。因此,这从$r
中提取了一系列术语,这些术语是$N
或其他,以其原始顺序和所有内容(除了尾随空格)保留。这包括可能的(前导)空字符串,因此需要将其过滤掉。
然后$N
以外的每个术语都包含在'...'
中,所以当它们全部由.
加入时,我们会得到一个有效的Perl表达式,如上例所示。
然后/ee
将使此函数返回字符串(如上所示),并将其评估为有效代码。
我们被告知在外部输入上使用/ee
的安全性不是问题。不过,这是值得记住的。请参阅this post在评论中提供的Håkon Hægland。除了讨论,它还指导我们String::Substitution。它的用法在this post中得到证明。另一种方法是使用Data::Munge
replace
有关/ee
的更多讨论,请参阅this post,并提供一些有用的答案。
关于将"b(.)d"
用于正则表达式
在这种情况下,使用parens和dot,可以保持其特殊含义。感谢kangshiyin尽早提及此问题,并感谢Håkon Hægland声明它。但是,这是一个特例。自插值完成后,双引号字符串直接拒绝许多模式 - 例如,"\w"
只是一个转义w
(无法识别的内容)。 单引号应该有效,因为没有插值。尽管如此,用作正则表达式模式的字符串最好使用qr
形成,因为我们正在获得真正的正则表达式。然后也可以使用所有修饰符。