使用外部参数进行Perl正则表达式替换

Non*_*ame 6 regex perl substitution

请考虑以下示例:

my $text = "some_strange_thing";
$text =~ s/some_(\w+)_thing/no_$1_stuff/;
print "Result: $text\n";  
Run Code Online (Sandbox Code Playgroud)

它打印

"结果:没有奇怪的 _粮"

到现在为止还挺好.

现在,我需要从外部源(用户输入,配置文件等)获取匹配和替换模式.天真的解决方案似乎是这样的:

my $match = "some_(\\w+)_thing";
my $repl = "no_\$1_stuff";

my $text = "some_strange_thing";
$text =~ s/$match/$repl/;
print "Result: $text\n";  
Run Code Online (Sandbox Code Playgroud)

然而:

"结果:no_ $ 1 _stuff".

怎么了?如何通过外部提供的模式获得相同的结果?

Wik*_*żew 9

解决方案1: String::Substitution

使用String::Substitution:

use String::Substitution qw(gsub_modify);

my $find = 'some_(\w+)_thing';
my $repl = 'no_$1_stuff';
my $text = "some_strange_thing";
gsub_modify($text, $find, $repl);
print $text,"\n";
Run Code Online (Sandbox Code Playgroud)

替换字符串仅插入(松散使用的术语)编号匹配变量(如$1${12}).有关更多信息,请参阅"interpolate_match_vars".
该模块并不能保存或插值$&避免了"相当大的性能损失"(参见perlvar).

解决方案2: Data::Munge

这是Grinnz在下面的评论中提到的解决方案.

Data::Munge可以使用以下方法:

use Data::Munge;

my $find = qr/some_(\w+)_thing/;
my $repl = 'no_$1_stuff';
my $text = 'some_strange_thing';
my $flags = 'g';
print replace($text, $find, $repl, $flags);
# => no_strange_stuff
Run Code Online (Sandbox Code Playgroud)

解决方案3:快速的方式(如果替换不包含双引号并且不考虑安全性)

免责声明:我提供此解决方案,因为这种方法可以在网上找到,但其解释并未解释.不要在生产中使用它.

使用这种方法,您不能拥有包含"双引号的替换字符串,因为这相当于处理编写配置文件直接代码访问权限的人,因此不应向Web用户公开(如Daniel Martin所述)).

您可以使用以下代码:

#!/usr/bin/perl
my $match = qr"some_(\w+)_thing";
my $repl = '"no_$1_stuff"';
my $text = "some_strange_thing";
$text =~ s/$match/$repl/ee;
print "Result: $text\n";
Run Code Online (Sandbox Code Playgroud)

请参阅IDEONE演示

结果:

Result: no_strange_stuff
Run Code Online (Sandbox Code Playgroud)

你必须

  1. 声明替换,'"..."'以便$1以后可以评估
  2. 使用/ee强制变量的双重评价的替代品.

专门用于搜索和替换的s///e修饰符是评估修饰符.s///e将替换文本视为Perl代码,而不是双引号字符串.代码返回的值将替换匹配的子字符串.s///e如果您需要在替换文本的过程中进行一些计算,这将非常有用.

您可以使用qr实例化regex(qr"some_(\w+)_thing")的模式.

  • 请注意,为了以这种方式引用,您不能拥有包含""字符的repl.另外,请注意,这相当于处理编写配置文件的任何人直接访问代码,因此不要暴露这个对网络用户. (2认同)