2008-08-22 14 views
146

En Perl, ¿cuál es una buena manera de realizar un reemplazo en una cadena utilizando una expresión regular y almacenar el valor en una variable diferente, sin cambiar el original?¿Cómo realizo una sustitución Perl en una cadena mientras mantengo el original?

Por lo general, solo copio la cadena a una nueva variable y luego la ato a la expresión regular s/// que hace la sustitución en la nueva cadena, pero me preguntaba si hay una mejor manera de hacerlo.

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

Respuesta

203

Este es el idioma que siempre he utilizado 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 la nueva /rnon-destructive substitution modifier:

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

Nota: Las soluciones anteriores funciona sin g también. También funcionan con otros modificadores.

+5

Ya sea bajo uso estricto. Alcance mínimo de las variables ++ – ysth

+0

Me preguntaba si algo como 'mi $ new = $ _ for $ old = ~ s/foo/bar;' funcionaría? – Benoit

+1

@Benoit, creo que te refieres a 's/foo/bar/para mi $ newstring = $ oldstring;' Funciona, pero es mucho más extraño. – ikegami

41

La declaración:

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

es equivalente a:

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

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

use 5.013; 
#... 
my $newstring = $oldstring =~ s/foo/bar/gr; 
+3

¿Olvidaste el 'g' en tu mejor expresión regular? – mareoraft

-1

Si escribe Perl con use strict;, entonces verá que la línea de sincronización el impuesto no es válido, incluso cuando se declara.

Con:

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

que se 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 se 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"; 
+0

Si 'usa advertencias;' en lugar de '-w', obtiene un mayor control: por ejemplo, si desea desactivar temporalmente las advertencias en un bloque de código. –

19

Bajo use strict, dicen:

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

lugar.

8

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

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

+0

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

+0

La versión de una línea, si se ejecuta correctamente, no es asunto, verdadero. Pero ese es un problema aparte. –

+7

Puede pensar que es una concisión innecesaria, pero tener que escribir un nombre de variable dos veces para usarla una vez es el doble de la cantidad de puntos de falla. Es perfectamente legible para personas que conocen el idioma, e incluso está en nuestro curso Learning Perl. –

1

Odio foo and 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 
+2

¿En qué se diferencia esto del original? (Y creo que quieres '= ~ s'.) – Teepeemm

+0

Error de Clbuttic. La salida real de ese código es 'newword donotnewword newword donotnewword newword donotnewword' – Pascal

0

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

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

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