[英]How to Circumvent Perl's string escaping the replacement string in s/// when it's read from a file?
This question is similar to my last one , with one difference to make the toy script more similar to my actual one. 这个问题类似于我的上一个问题,只是使玩具脚本与我的实际脚本更加相似。
Here is the toy script, replace.pl ( Edit: now with 'use strict;', etc) 这是玩具脚本,replace.pl( 编辑:现在带有'use strict;',等等)
#! /usr/bin/perl -w
use strict;
open(REPL, "<", $ARGV[0]) or die "Couldn't open $ARGV[0]: $!!";
my %replacements;
while(<REPL>) {
chomp;
my ($orig, $new, @rest) = split /,/;
# Processing+sanitizing of orig/new here
$replacements{$orig} = $new;
}
close(REPL) or die "Couldn't close '$ARGV[0]': $!";
print "Performing the following replacements\n";
while(my ($k,$v) = each %replacements) {
print "\t$k => $v\n";
}
open(IN, "<", $ARGV[1]) or die "Couldn't open $ARGV[1]: $!!";
while ( <IN> ) {
while(my ($k,$v) = each %replacements) {
s/$k/$v/gee;
}
print;
}
close(IN) or die "Couldn't close '$ARGV[1]': $!";
So, now lets say I have two files, replacements.txt (using the best answer from the last question, plus a replacement pair that doesn't use substitution): 因此,现在让我们说我有两个文件,replaces.txt(使用上一个问题的最佳答案,以及不使用替代的替代对):
(f)oo,q($1."ar")
cat,hacker
and test.txt: 和test.txt:
foo
cat
When I run perl replace.pl replacements.txt test.txt
I would like the output to be 当我运行
perl replace.pl replacements.txt test.txt
我希望输出为
far
hacker
but instead it's ' $1."ar"
' (too much escaping) but the results are anything but (even with the other suggestions from that answer for the replacement string). 但是它是'
$1."ar"
'(太多的转义),但是结果却是什么(甚至还有该替换字符串的答案)。 The foo
turns into ar, and the cat/hacker is eval'd to the empty string, it seems. 看起来
foo
变成了ar,而cat / hacker被评估为空字符串。
So, what changes do I need to make to replace.pl and/or replacements.txt? 那么,我需要对replace.pl和/或replaces.txt进行哪些更改? Other people will be creating the replacements.txt's, so I'd like to make that file as simple as possible (although I acknowledge that I'm opening the regex can of worms on them).
其他人将创建replaces.txt的文件,因此,我希望使该文件尽可能简单(尽管我承认我正在蠕虫上打开正则表达式罐头)。
If this isn't possible to do in one step, I'll use macros to enumerate all possible replacement pairs for this particular file, and hope the issue doesn't come up again. 如果一步不可能做到这一点,我将使用宏来枚举此特定文件的所有可能的替换对,并希望问题不再出现。
Please don't give us non-working toy scripts that don't use strict and warnings. 请不要给我们不使用严格和警告的不起作用的玩具脚本。 Because one of the first things people will do in debugging is to turn those on, and you've just caused work.
因为人们在调试中要做的第一件事就是将它们打开,所以您已经完成了工作。
Second tip, use the 3-argument version of open rather than the 2-argument version. 第二个技巧是使用open的3参数版本而不是2参数版本。 It is safer.
更安全。 Also in your error checking do as perlstyle says (see http://perldoc.perl.org/perlstyle.html for the full advice) and include the file name and $!.
同样在错误检查中,按照perlstyle的说明进行操作(有关完整建议,请参见http://perldoc.perl.org/perlstyle.html ),并包括文件名和$!。
Anyways your problem is that the code you were including was q($1."ar"). 无论如何,您的问题是所包含的代码是q($ 1。“ ar”)。 When executed this returns the string $1."ar".
执行时返回字符串$ 1。“ ar”。 Get rid of the q() and it works fine.
摆脱q(),它可以正常工作。 BUT it causes warnings.
但是会引起警告。 That can be fixed by moving the quoting into the replace script, and out of the original script.
可以通过将引用移到替换脚本中,再移出原始脚本来解决此问题。
Here is a fixed script for you: 这是给您的固定脚本:
#! /usr/bin/perl -w
use strict;
open(REPL, "<", $ARGV[0]) or die "Couldn't open '$ARGV[0]': $!!";
my %replacements;
while(<REPL>) {
chomp;
my ($orig, $new) = split /,/;
# Processing+sanitizing of orig/new here
$replacements{$orig} = '"' . $new . '"';
}
close(REPL) or die "Couldn't close '$ARGV[0]': $!";
print "Performing the following replacements\n";
while(my ($k,$v) = each %replacements) {
print "\t$k => $v\n";
}
open(IN, "<", $ARGV[1]) or die "Couldn't open '$ARGV[1]': $!!";
while ( <IN> ) {
while(my($k,$v) = each %replacements) {
s/$k/$v/gee;
}
print;
}
close(IN) or die "Couldn't close '$ARGV[1]': $!";
And the modified replacements.txt is: 修改后的replacements.txt是:
(f)oo,${1}ar
cat,hacker
You have introduced one more level of interpolation since the last question. 自上一个问题以来,您已经引入了一个更高级别的插值。 You can get the right result by either:
您可以通过以下任一方式获得正确的结果:
Lay a 3rd "e" modifier on your substitution 在替换中放置第三个“ e”修饰符
s/$k/$v/geee;S / $ K / $ V / geee; # eeek
#eeek
Remove a layer of interpolation in replacements.txt
by making the first line 通过制作第一行,在
replacements.txt
删除插值层
(f)oo,$1."ar"(六)OO,$ 1。 “AR”
Get rid of the q() in the replacement string; 摆脱替换字符串中的q();
Should be just 应该只是
(f)oo,$1."ar"
as in ($k,$v) = split /,/, $_;
如
($k,$v) = split /,/, $_;
Warning: using external input data in evals is very, very dangerous 警告:在评估中使用外部输入数据非常非常危险
Or, just make it 或者,只是做到
(f)oo,"${1}ar"
No modification to the code is necessary either way eg s///gee. 两种方式都不需要修改代码,例如s /// gee。
Edit @drhorrible, if it doesen't work then you have other problems. 编辑 @drhorrible,如果它不起作用,那么您还有其他问题。
use strict;use warnings;
my $str = "foo";
my $repl = '(f)oo,q(${1}."ar")';
my ($k,$v) = split /,/, $repl;
$str =~ s/$k/$v/gee;
print $str,"\n";
$str = "foo";
$repl = '(f)oo,$1."ar"';
($k,$v) = split /,/, $repl;
$str =~ s/$k/$v/gee;
print $str,"\n";
$str = "foo";
$repl = '(f)oo,"${1}ar"';
($k,$v) = split /,/, $repl;
$str =~ s/$k/$v/gee;
print $str,"\n";
output: 输出:
${1}."ar"
far
far
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.