Perl: use referencias inversas en una variable de cadena de reemplazo
Estoy realizando una sustitución de cadenas en Perl, pero tengo tanto el patrón como las cadenas de reemplazo almacenadas como variables escalares fuera de los operadores de expresiones regulares. El problema es que quiero que la cadena de reemplazo pueda usar referencias inversas.
Espero que el siguiente código ilustre el asunto más claramente.
my $pattern = 'I have a pet (\w+).';
my $replacement = 'My pet $1 is a good boy.';
my $original_string = 'I have a pet dog.';
# Not Working
my $new_string = $original_string =~ s/$pattern/$replacement/r;
# Working
#my $new_string = $original_string =~ s/$pattern/My pet $1 is a good boy./r;
# Expected: "My pet dog is a good boy."
# Actual: "My pet $1 is a good boy."
print "$new_string\n";
Respuestas
s/$pattern/My pet $1 is a good boy./
es corto para
s/$pattern/ "My pet $1 is a good boy." /e
La expresión de reemplazo ( "My pet $1 is a good boy."
) es un literal de cadena que interpola $1
.
Esto significa que
s/$pattern/$replacement/
es corto para
s/$pattern/ "$replacement" /e
La expresión de reemplazo ( "$replacement"
) es un literal de cadena que interpola $replacement
(no $1
).
Si bien puede ser un obstáculo para usted, es bueno que perl
no tenga la costumbre de ejecutar el contenido de las variables como código Perl. :)
Puede usar gsub_copy
desde String::Substitution para resolver su problema.
use String::Subtitution qw( gsub_copy );
my $pattern = 'I have a pet (\w+)\.';
my $replacement = 'My pet $1 is a good boy.';
my $original_string = 'I have a pet dog.';
my $new_string = gsub_copy($original_string, $pattern, $replacement);
Eso $1
en la cadena de reemplazo es solo caracteres sucesivos $
y 1
, y para convertirlo en una variable para la primera captura, tendría que pasar por malos aros. †
¿Qué tal una alternativa?
my string = q(a pet dog);
my $pattern = qr/a pet (\w+)/;
my $new = $string =~ s/$pattern/ repl($1) /er;
sub repl {
my ($capture) = @_;
return "$capture is a good boy";
}
donde el submarino es realmente solo
sub repl { "$_[0] is a good boy" }
Es un poco más, pero luego es más capaz y flexible.
† O, como resulta según la respuesta de ikegami, use String::Substitution que envuelve todas las 'sutilezas' involucradas en una sola llamada