如何在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式的结尾:
- $ sub – > $ 1
- $ 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/;
也就是说,只留下中间的一个,取代开始和结束。