Как обойти строку Perl, экранирующую строку замены в s ///, когда она читается из файла? - PullRequest
0 голосов
/ 03 февраля 2011

Этот вопрос похож на мой последний , с одним отличием, чтобы сделать игрушечный сценарий более похожим на мой настоящий.

Вот игрушечный скрипт, replace.pl ( Редактировать: теперь с «Использовать строгий;» и т. Д.)

#! /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]': $!";

Итак, теперь допустим, что у меня есть два файла replacements.txt (используется лучший ответ из последнего вопроса плюс пара замен, не использующая подстановку):

(f)oo,q($1."ar")
cat,hacker

и test.txt:

foo
cat

Когда я запускаю perl replace.pl replacements.txt test.txt, я бы хотел, чтобы результат был

far
hacker

но вместо этого это '$1."ar"' (слишком много экранирования), но результаты совсем не похожи (даже с другими предложениями из этого ответа для строки замены). foo превращается в ar, и, кажется, кот / хакер равен пустой строке.

Итак, какие изменения мне нужно сделать, чтобы заменить .pl и / или replacements.txt? Другие люди будут создавать файл replacements.txt, поэтому я хотел бы сделать этот файл как можно более простым (хотя я признаю, что открываю для них червь регулярных выражений).

Если это невозможно сделать за один шаг, я буду использовать макросы для перечисления всех возможных пар замены для этого конкретного файла и надеюсь, что проблема больше не возникнет.

Ответы [ 3 ]

4 голосов
/ 03 февраля 2011

Пожалуйста, не давайте нам нерабочих игрушечных скриптов, которые не используют строгие и предупреждения. Потому что первое, что люди сделают при отладке, - это включите их, а вы только что вызвали работу.

Второй совет, используйте версию open с 3 аргументами, а не версию с 2 аргументами. Это безопаснее. Также при проверке ошибок сделайте, как говорит perlstyle (полный совет см. В http://perldoc.perl.org/perlstyle.html), и включите имя файла и $!.

В любом случае, ваша проблема в том, что код, который вы включали, был q ($ 1. "Ar"). При выполнении это возвращает строку $ 1. "Ar". Избавьтесь от q () и все работает отлично. НО вызывает предупреждения. Это можно исправить, переместив цитату в скрипт замены и из оригинального скрипта.

Вот фиксированный скрипт для вас:

#! /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]': $!";

И измененный файл replacements.txt:

(f)oo,${1}ar
cat,hacker
0 голосов
/ 03 февраля 2011

Избавиться от q () в строке замены;

Должно быть просто
(f)oo,$1."ar"
, как в ($k,$v) = split /,/, $_;

Предупреждение: использованиевнешние входные данные в evals очень, очень опасны

Или просто сделайте это
(f)oo,"${1}ar"

Никаких изменений в коде в любом случае не требуется, например, s ///gee.

Редактировать @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";

вывод:
${1}."ar"
far
far

0 голосов
/ 03 февраля 2011

Вы ввели еще один уровень интерполяции со времени последнего вопроса. Вы можете получить правильный результат одним из следующих способов:

  1. Положите 3-й модификатор "е" на вашу замену

    s/$k/$v/geee;    # eeek
  2. Удалите слой интерполяции в replacements.txt, сделав первую строку

    (f)oo,$1."ar"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...