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


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?

Normalmente solo copio la cadena a una nueva variable y luego la enlazo a la s/// regex que hace el reemplazo en la nueva cadena, pero me preguntaba si hay una mejor manera de hacer esto?

$newstring = $oldstring;
$newstring =~ s/foo/bar/g;
Author: the Tin Man, 2008-08-22

7 answers

Este es el modismo 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 utilizar el nuevo /r modificador de sustitución no destructivo:

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

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

 214
Author: John Siracusa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-22 16:41:11

La declaración:

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

Que es equivalente a:

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

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

use 5.013;
#...
my $newstring = $oldstring =~ s/foo/bar/gr;
 41
Author: Pat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-30 17:13:22

En use strict, diga:

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

En su lugar.

 19
Author: Sam Kington,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-01 18:09:37

La solución de una línea es más útil como 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 pareado de copia y modificación de dos líneas con el que está comenzando.

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

 9
Author: Josh Millard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-28 20:29:12

Odio foo y bar .. ¿quién inventó 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
 1
Author: JoGotta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-05 19:17:53

Otra solución pre-5.14: http://www.perlmonks.org/?node_id=346719 (ver el post de japhy)

Como su enfoque utiliza map, también funciona bien para matrices, pero requiere en cascada map para producir una matriz temporal (de lo contrario, el original sería modificado):

my @orig = ('this', 'this sucks', 'what is this?');
my @list = map { s/this/that/; $_ } map { $_ } @orig;
# @orig unmodified
 0
Author: textral,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-25 06:14:25

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

Con:

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

Obtienes:

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, mientras que una línea más larga, es la forma sintácticamente correcta de hacerlo con use strict;. Para mí, usar use strict; es solo un hábito ahora. Lo hago automáticamente. 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";
 -1
Author: Tim Kennedy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-01 18:11:37