pattern regex perl substitution

regex - pattern - ¿Cómo usar una variable en el lado de reemplazo del operador de sustitución de Perl?



matching pattern perl (8)

Como otros han sugerido, puede usar lo siguiente:

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;

Lo anterior es corto para lo siguiente:

my $find = ''start (.*) end''; my $replace = ''foo $1 bar''; my $var = "start middle end"; $var =~ s/$find/ eval($replace) /e;

Prefiero el segundo al primero, ya que no oculta el hecho de que se usa eval(EXPR) . Sin embargo, los dos errores de silencio anteriores, por lo que lo siguiente sería mejor:

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;

Pero como puede ver, todo lo anterior permite la ejecución de código Perl arbitrario. Lo siguiente sería mucho más seguro:

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

Me gustaría hacer lo siguiente:

$find="start (.*) end"; $replace="foo /1 bar"; $var = "start middle end"; $var =~ s/$find/$replace/;

Esperaría $ var contener "foo middle bar", pero no funciona. Tampoco lo hace:

$replace=''foo /1 bar'';

De alguna manera me falta algo sobre el escape.

Arreglé los "faltantes"


Deparse nos dice que esto es lo que se está ejecutando:

$find = ''start (.*) end''; $replace = "foo /cA bar"; $var = ''start middle end''; $var =~ s/$find/$replace/;

Sin embargo,

/$find/foo /1 bar/

Se interpreta como:

$var =~ s/$find/foo $1 bar/;

Desafortunadamente, parece que no hay una manera fácil de hacerlo.

Puedes hacerlo con una evaluación de cadena, pero eso es peligroso.

La solución más sensata que funciona para mí fue esta:

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

Una refutación contra la técnica ee:

Como dije en mi respuesta, evito las evaluaciones por una razón.

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

este código hace exactamente lo que crees que hace.

Si su cadena de sustitución está en una aplicación web, acaba de abrir la puerta a la ejecución de código arbitrario.

Buen trabajo.

Además, NO funcionará con las manchas activadas por esta misma razó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.

Sin embargo, la técnica más cuidadosa es sensata, segura y no contamina. (Tenga la seguridad de que la cadena que emite todavía está contaminada, por lo que no pierde seguridad).


En el lado de reemplazo, debe usar $ 1, no / 1.

Y solo puede hacer lo que quiera haciendo que replace sea una expresión evalable que le dé el resultado que desea y diciéndole a s /// que lo evalúe con el modificador / ee de la siguiente manera:

$find="start (.*) end"; $replace=''"foo $1 bar"''; $var = "start middle end"; $var =~ s/$find/$replace/ee; print "var: $var/n";

Para ver por qué se necesitan "" y double / e, vea el efecto de la doble evaluación aquí:

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


No estoy seguro de qué es lo que estás tratando de lograr. Pero tal vez puedas usar esto:

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

Es decir, dejo solo el medio y reemplazo el inicio y el final.


Sugeriría algo como:

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

Es bastante legible y parece ser seguro. Si se necesita reemplazo múltiple, es fácil:

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


Vea ESTA publicación anterior SO sobre el uso de una variable en el lado de reemplazo de s/// en Perl. Mire tanto la respuesta aceptada como la respuesta de rebuttal .

Lo que intenta hacer es posible con el formulario s///ee que realiza una doble eval en la cadena de la derecha. Consulte la cotización perlop como operadores para más ejemplos.

Tenga en cuenta que existen impILcaciones de seguridad de eval y que esto no funcionará en el modo de contaminación.


# perl -de 0 $match="hi(.*)" $sub=''$1'' $res="hi1234" $res =~ s/$match/$sub/gee p $res 1234

Ten cuidado, sin embargo. Esto provoca que se produzcan dos capas de eval , una para cada e al final de la expresión regular:

  1. $ sub -> $ 1
  2. $ 1 -> valor final, en el ejemplo, 1234

#!/usr/bin/perl $sub = "//1"; $str = "hi1234"; $res = $str; $match = "hi(.*)"; $res =~ s/$match/$1/g; print $res

Esto me dio el ''1234''.