简体   繁体   English

从文件中读取Perl的字符串时如何绕过s ///中的替换字符串?

[英]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: 您可以通过以下任一方式获得正确的结果:

  1. Lay a 3rd "e" modifier on your substitution 在替换中放置第三个“ e”修饰符

     s/$k/$v/geee; S / $ K / $ V / geee; # eeek #eeek 
  2. 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.

相关问题 如何绕过Perl的字符串转义s ///中的替换字符串? - How to Circumvent Perl's string escaping the replacement string in s///? 使用正则表达式在Java字符串中转义文字 - escaping literal's in java string using regex 为TextMate的$ DIALOG命令转义Ruby字符串 - Escaping a Ruby String for TextMate's $DIALOG command 如何使perl识别带有几个|的字符串 在它作为单个字符串? - How to make perl recognize a string with several | 's in it as a single string? 我来自 csv 文件的文本被读取为原始字符串。 它包含“it\'s”而不是 it's。 我该如何清洁这个? - My text from csv file is being read as raw string. It contains “it\'s” instead of it's. How do I clean this? Perl元编程:何时在s ///的REPLACEMENT值上使用quotemeta是不安全的? - Perl metaprogramming: when is it unsafe to use quotemeta on the REPLACEMENT value of s///? 如何将一些字符串映射到另一个字符串并在perl中打印输出 - how to map some string(s) into another and print output in perl 如何使用Perl的正则表达式遍历多行字符串 - How to iterate over a multiline string with perl's regex 转义字符串在Perl中引用 - Escaping string to be quoted in Perl 如何删除字符串中的“&#39;s”? - How to remove “ 's” in a string?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM