Как использовать переменную в заменяющей стороне оператора замены Perl?

delete[] вызовет деструктор каждого элемента массива.

Именно поэтому используются интеллектуальные указатели: delete[] вызовет деструктор каждого элемента, а деструктор - умного указателя вызовет delete на управляемом указателе.

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

45
задан Jonathan Leffler 26 December 2008 в 05:43
поделиться

7 ответов

На заменяющей стороне необходимо использовать 1$, не \1.

И можно только сделать то, что Вы хотите путем создания замены evalable выражением, которое дает результат, который Вы хотите и говорящий s///к оценке она с/ee модификатором как так:

$find="start (.*) end";
$replace='"foo $1 bar"';

$var = "start middle end";
$var =~ s/$find/$replace/ee;

print "var: $var\n";

Для наблюдения, почему "" и удваивают/e, необходимы, видят эффект двойной оценки здесь:

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

(Хотя как ikegami примечания, единственный/e или первый/e двойного e не действительно eval(); скорее это говорит компилятору, что замена является кодом для компиляции, не строка. Тем не менее, eval(eval(...)) все еще демонстрирует, почему необходимо сделать то, что необходимо сделать, чтобы заставить/ee работать, как желаемый.)

76
ответ дан ysth 8 November 2019 в 00:58
поделиться

Я не уверен относительно того, что это, Вы пытаетесь достигнуть. Но возможно можно использовать это:

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

Т.е. просто оставляют середину в покое и заменяют запуск и конец.

-5
ответ дан PEZ 8 November 2019 в 00:58
поделиться

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/;

К сожалению, кажется, что нет никакого простого способа сделать это.

Можно сделать это со строковой оценкой, но это опасно.

Самое нормальное решение, которое работает на меня, было этим:

$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 техники:

Как я сказал в своем ответе, я избегаю evals по причине.

$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";

этот код делает точно, что Вы думаете, что он делает.

Если Ваша строка замены находится в веб-приложении, Вы просто открыли дверь в выполнение произвольного кода.

Хорошее задание.

Кроме того, это не будет работать с инфекциями, включенными по этой самой причине.

$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.

Однако более осторожная техника нормальна, безопасна, безопасна, и не приводит инфекцию к сбою. (Уверьте tho, строка, которую он испускает, все еще испорчена, таким образом, Вы не теряете безопасности.)

12
ответ дан Kent Fredric 26 November 2019 в 21:08
поделиться

Я бы предложил бы что-то вроде:

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

это довольно читаемо и кажется, безопасно. Если необходима несколько замене, это легко:

while ($text =~ m{(.*)$find(.*)}){
     $text = $1 . $replace . $2;
}
1
ответ дан 26 November 2019 в 21:08
поделиться

См. ЭТО предыдущий пост SO об использовании переменной на стороне замены s /// в Perl. Посмотрите как на принятый ответ , так и на опровержение .

То, что вы пытаетесь сделать, возможно с помощью формы s /// ee , которая выполняет двойной eval в правой строке. Дополнительные примеры см. В perlop quote like операторах .

Имейте в виду, что существуют угрозы безопасности eval , и это не будет работать в режиме заражения.

1
ответ дан 26 November 2019 в 21:08
поделиться
#!/usr/bin/perl

$sub = "\\1";
$str = "hi1234";
$res = $str;
$match = "hi(.*)";
$res =~ s/$match/$1/g;

print $res

Это дало мне '1234'.

0
ответ дан 26 November 2019 в 21:08
поделиться
# perl -de 0
$match="hi(.*)"
$sub='$1'
$res="hi1234"
$res =~ s/$match/$sub/gee
p $res
  1234

Но будьте осторожны. Это вызывает появление двух уровней eval , по одному для каждого e в конце регулярного выражения:

  1. $ sub -> $ 1
  2. $ 1 -> final value , в примере 1234
7
ответ дан 26 November 2019 в 21:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: