¿Cómo realizo una sustitución de Perl en una cadena mientras mantengo el original?

180

En Perl, ¿cuál es una buena manera de realizar un reemplazo en una cadena usando una expresión regular y almacenar el valor en una variable diferente, sin cambiar el original?

Por lo general, solo copie la cadena a una nueva variable y luego la s///asocio a la expresión regular que reemplaza la nueva cadena, pero me preguntaba si hay una mejor manera de hacer esto.

$newstring = $oldstring;
$newstring =~ s/foo/bar/g;
kaybenleroll
fuente

Respuestas:

257

Este es el idioma que siempre he usado para obtener una copia modificada de una cadena sin cambiar el original:

(my $newstring = $oldstring) =~ s/foo/bar/g;

En perl 5.14.0 o posterior, puede usar el nuevo /r modificador de sustitución no destructivo :

my $newstring = $oldstring =~ s/foo/bar/gr; 

Nota: Las soluciones anteriores también funcionan sin ellas g. También funcionan con cualquier otro modificador.

John Siracusa
fuente
66
Ya sea bajo uso estricto o no.
Ámbito
Me preguntaba si algo así my $new = $_ for $old =~ s/foo/bar;funcionaría.
Benoit
2
@Benoit, creo que quieres decir que s/foo/bar/ for my $newstring = $oldstring;funciona, pero es mucho más raro.
ikegami
43

La declaración:

(my $newstring = $oldstring) =~ s/foo/bar/g;

Lo que es equivalente a:

my $newstring = $oldstring;
$newstring =~ s/foo/bar/g;

Alternativamente, a partir de Perl 5.13.2 puede usar /rpara hacer una sustitución no destructiva:

use 5.013;
#...
my $newstring = $oldstring =~ s/foo/bar/gr;
Palmadita
fuente
3
¿Olvidaste el gen tu expresión regular superior?
mareoraft
23

Debajo use strict, di:

(my $new = $original) =~ s/foo/bar/;

en lugar.

Sam Kington
fuente
10

La solución de una línea es más útil como un shibboleth que un buen código; los buenos codificadores de Perl lo sabrán y lo entenderán, pero es mucho menos transparente y legible que el acoplado de dos líneas para copiar y modificar con el que está comenzando.

En otras palabras, una buena manera de hacerlo es la forma en que ya lo estás haciendo. La concisión innecesaria a costa de la legibilidad no es una victoria.

Josh Millard
fuente
Ah, pero la versión de una línea no está sujeta al error en la cuestión de modificar involuntariamente la cadena incorrecta.
ysth
La versión de una línea, <i> si se ejecuta correctamente </i>, no es asunto, es verdad. Pero ese es un tema aparte.
Josh Millard
9
Puede pensar que es una concisión innecesaria, pero tener que escribir un nombre de variable dos veces para usarlo una vez es el doble de puntos de falla. Es perfectamente legible para las personas que conocen el idioma, e incluso está en nuestro curso <i> Learning Perl </i>.
brian d foy
1

Otra solución anterior a la 5.14: http://www.perlmonks.org/?node_id=346719 (ver la publicación de japhy)

A medida que utiliza su enfoque map, también funciona bien para las matrices, pero requiere una conexión mapen cascada para producir una matriz temporal (de lo contrario, el original se modificaría):

my @orig = ('this', 'this sucks', 'what is this?');
my @list = map { s/this/that/; $_ } map { $_ } @orig;
# @orig unmodified
textral
fuente
1

Odio foo y bar ... ¿quién soñó estos términos no descriptivos en la programación de todos modos?

my $oldstring = "replace donotreplace replace donotreplace replace donotreplace";

my $newstring = $oldstring;
$newstring =~ s/replace/newword/g; # inplace replacement

print $newstring;
%: newword donotreplace newword donotreplace newword donotreplace
JoGotta
fuente
2
¿Cómo es esto diferente del original? (Y creo que quieres =~ s.)
Teepeemm
Error clutico. La salida real de ese código esnewword donotnewword newword donotnewword newword donotnewword
Pascal
2
Mira ... si JoGotta hubiera usado lo tradicional y familiar fooy barsu respuesta hubiera sido precisa. Demostrando, una vez más, las costumbres existen por una razón y las lecciones solo se aprenden de la manera difícil. ;)
Jon
-1

Si escribe Perl con use strict;, encontrará que la sintaxis de una línea no es válida, incluso cuando se declara.

Con:

my ($newstring = $oldstring) =~ s/foo/bar/;

Usted obtiene:

Can't declare scalar assignment in "my" at script.pl line 7, near ") =~"
Execution of script.pl aborted due to compilation errors.

En cambio, la sintaxis que ha estado utilizando, aunque es una línea más larga, es la forma sintácticamente correcta de hacerlo use strict;. Para mí, usar use strict;es solo un hábito ahora. Lo hago de forma automática. Todos deberían.

#!/usr/bin/env perl -wT

use strict;

my $oldstring = "foo one foo two foo three";
my $newstring = $oldstring;
$newstring =~ s/foo/bar/g;

print "$oldstring","\n";
print "$newstring","\n";
Tim Kennedy
fuente
1
Si en use warnings;lugar de eso -w, obtiene un mayor control: por ejemplo, si desea desactivar temporalmente las advertencias en un bloque de código.
Glenn Jackman