如何在Perlreplace运算符的replace侧使用variables?

我想要做以下事情:

$find="start (.*) end"; $replace="foo \1 bar"; $var = "start middle end"; $var =~ s/$find/$replace/; 

我希望$ var包含“foo中间栏”,但它不起作用。 也不:

 $replace='foo \1 bar'; 

不知何故,我失去了一些有关逃跑。


我修复了失踪的'

在replace方面,您必须使用$ 1,而不是\ 1。

而且你只能做你想做的事情,通过replace一个可以自由expression的结果,然后告诉s ///用ee修饰符来评估它,像这样:

 $find="start (.*) end"; $replace='"foo $1 bar"'; $var = "start middle end"; $var =~ s/$find/$replace/ee; print "var: $var\n"; 

要明白为什么需要“”和double / e,请看这里的double eval的效果:

 $ perl $foo = "middle"; $replace='"foo $foo bar"'; print eval('$replace'), "\n"; print eval(eval('$replace')), "\n"; __END__ "foo $foo bar" foo middle bar 

Deparse告诉我们这是执行的内容:

 $find = 'start (.*) end'; $replace = "foo \cA bar"; $var = 'start middle end'; $var =~ s/$find/$replace/; 

然而,

  /$find/foo \1 bar/ 

被解释为:

 $var =~ s/$find/foo $1 bar/; 

不幸的是,似乎没有简单的方法来做到这一点。

你可以做一个string评估,但那是危险的。

对我来说最合理的解决scheme是这样的:

 $find = "start (.*) end"; $replace = 'foo \1 bar'; $var = "start middle end"; sub repl { my $find = shift; my $replace = shift; my $var = shift; # Capture first my @items = ( $var =~ $find ); $var =~ s/$find/$replace/; for( reverse 0 .. $#items ){ my $n = $_ + 1; # Many More Rules can go here, ie: \g matchers and \{ } $var =~ s/\\$n/${items[$_]}/g ; $var =~ s/\$$n/${items[$_]}/g ; } return $var; } print repl $find, $replace, $var; 

反对ee技术的反驳:

正如我在答复中所说,我避免出于某种原因而作出的反应。

 $find="start (.*) end"; $replace='do{ print "I am a dirty little hacker" while 1; "foo $1 bar" }'; $var = "start middle end"; $var =~ s/$find/$replace/ee; print "var: $var\n"; 

这段代码的确如你所想的那样。

如果你的replacestring是在一个Web应用程序中,你只是打开了执行任意代码的大门。

做得好。

而且,由于这个原因,它不会与打开的黑洞一起工作。

 $find="start (.*) end"; $replace='"' . $ARGV[0] . '"'; $var = "start middle end"; $var =~ s/$find/$replace/ee; print "var: $var\n" $ perl /tmp/re.pl 'foo $1 bar' var: foo middle bar $ perl -T /tmp/re.pl 'foo $1 bar' Insecure dependency in eval while running with -T switch at /tmp/re.pl line 10. 

然而,更谨慎的技术是理智的,安全的,安全的,不污染的。 (请放心,它发出的string仍然被污染,所以你不会失去任何安全。)

 # perl -de 0 $match="hi(.*)" $sub='$1' $res="hi1234" $res =~ s/$match/$sub/gee p $res 1234 

不过要小心。 这会导致出现两个eval层,每个e在正则expression式的结尾:

  1. $ sub – > $ 1
  2. $ 1 – >最终值,在这个例子中,1234

正如其他人所build议的,您可以使用以下内容:

 my $find = 'start (.*) end'; my $replace = 'foo $1 bar'; # 'foo \1 bar' is an error. my $var = "start middle end"; $var =~ s/$find/$replace/ee; 

以上是短暂的以下内容:

 my $find = 'start (.*) end'; my $replace = 'foo $1 bar'; my $var = "start middle end"; $var =~ s/$find/ eval($replace) /e; 

我更喜欢第二个到第一个,因为它并不隐藏eval(EXPR)被使用的事实。 但是,上述两个沉默错误,所以下面会更好:

 my $find = 'start (.*) end'; my $replace = 'foo $1 bar'; my $var = "start middle end"; $var =~ s/$find/ my $r = eval($replace); die $@ if $@; $r /e; 

但是正如你所看到的,所有上述都允许执行任意的Perl代码。 以下将更安全:

 use String::Substitution qw( sub_modify ); my $find = 'start (.*) end'; my $replace = 'foo $1 bar'; my $var = "start middle end"; sub_modify($var, $find, $replace); 

我会build议像这样的东西:

 $text =~ m{(.*)$find(.*)}; $text = $1 . $replace . $2; 

这是相当可读的,似乎是安全的。 如果需要多个replace,很容易:

 while ($text =~ m{(.*)$find(.*)}){ $text = $1 . $replace . $2; } 

请参阅本文以前的post,在Perl的s///replace端使用variables。 看看接受的答案和反驳的答案。

你正在试图做的是可以用s///ee表单对右边的string进行双重eval 。 有关更多示例,请参阅运算符一样的perlop引号 。

被警告说有eval安全隐患,这不会在污染模式下工作。

 #!/usr/bin/perl $sub = "\\1"; $str = "hi1234"; $res = $str; $match = "hi(.*)"; $res =~ s/$match/$1/g; print $res 

这让我'1234'。

我不确定你想要达到的目标。 但也许你可以使用这个:

 $var =~ s/^start/foo/; $var =~ s/end$/bar/; 

也就是说,只留下中间的一个,取代开始和结束。