2010-07-25 19 views
9

¿Hay alguna manera de reemplazar texto con una expresión regular en línea, en lugar de tomar el texto de una variable y almacenarlo en una variable?Reemplazo de regex en línea en Perl

Soy un principiante perl. A menudo me encuentro escribiendo

my $foo = $bar; 
$foo =~ s/regex/replacement/; 
doStuff($foo) 

donde realmente me gustaría escribir

doStuff($bar->replace(s/regex/replacement/)); 

o similares, en lugar de utilizar una variable temporal y tres líneas.

¿Hay alguna manera de hacerlo? Obviamente, cuando la expresión regular es suficientemente complicada, tiene sentido dividirla para que se pueda explicar mejor, pero cuando solo es s/\s//g, parece incorrecto desordenar el código con variables adicionales.

+1

duplicados http://stackoverflow.com/questions/3321400/how-to-do-perl-inline-regex-without-setting-to-a- variable – daxim

Respuesta

2

Se puede utilizar un bloque de do { } para evitar crear una variable temporal en el ámbito actual:

doStuff(do {(my $foo = $bar) =~ s/regex/replacement/; $foo}); 
+0

Así que aparentemente lo que quiero no es posible sin el desorden o mi propia función. (Es bastante fácil escribir eso, pero eso hace que sea más difícil para otros escanear; no conocerán la semántica de mi función). – Charles

+3

La idea era aclarar los resultados. Hacer lo que está mostrando todavía usa una variable temporal '$ foo', y hace que el programa sea más difícil de entender. Creo que lo que el póster realmente quería hacer era evitar tener que crear un '$ foo' temporal para poner en la función doStuff. –

0

¿Es esto lo que quieres ?:

my $foo = 'Replace this with that'; 
(my $bar = $foo) =~ s/this/that/; 
print "Foo: $foo\nBar: $bar\n"; 

Lienzo:

Foo: Replace this with that 
Bar: Replace that with that 
+0

Eso guarda una línea al poner la definición junto con la sustitución, pero aún usa una temporal. ¿Es imposible evitar esto? – Charles

14

Realmente no puede hacer lo que desea porque la función de sustitución devuelve 1 si funcionó o una cadena vacía si no funcionó. Esto significa que si usted hizo esto:

doStuff($foo =~ s/regex/replacement/); 

La función doStuff estaría utilizando ya sea 1 o una cadena vacía como parámetro. No hay ninguna razón por la cual la función de sustitución no pueda devolver la cadena resultante en lugar de solo 1 si funcionó. Sin embargo, fue una decisión de diseño desde los primeros días de Perl. De lo contrario, ¿qué pasaría con esto?

$foo = "widget"; 
if ($foo =~ s/red/blue/) { 
    print "We only sell blue stuff and not red stuff!\n"; 
} 

La cadena resultante es todavía widget, pero la sustitución fallado en realidad. Sin embargo, si la sustitución devolviera la cadena resultante y no una cadena vacía, el if seguiría siendo verdadero.

Entonces, considere este caso:

$bar = "FOO!"; 
if ($bar =~ s/FOO!//) { 
    print "Fixed up \'\$bar\'!\n"; 
} 

$bar es ahora una cadena vacía. Si la sustitución devuelve el resultado, devolverá una cadena vacía. Sin embargo, la sustitución realmente tuvo éxito y quiero que mi if sea cierto.

En la mayoría de los idiomas, la función de sustitución devuelve la cadena resultante, y que tendría que hacer algo como esto:

if ($bar != replace("$bar", "/FOO!//")) { 
    print "Fixed up \'\$bar''!\n"; 
} 

Por lo tanto, debido a una decisión de diseño de Perl (básicamente para imitar mejor awk sintaxis) , no hay una manera fácil de hacer lo que quieres.Sin embargo se podría haber hecho esto:

($foo = $bar) =~ s/regex/replacement/; 
doStuff($foo); 

Eso haría un lugar en el establecimiento de $foo sin antes asignándole el valor de $bar. $bar se mantendrían sin cambios.

+0

Qué decepcionante. Gracias por la respuesta muy completa. – Charles

+2

Técnicamente, 's ///' devuelve el número de sustituciones realizadas (o la cadena vacía si es 0). Pero si no usa '/ g', obviamente eso no puede ser más que 1. – cjm

+2

Teóricamente, podría tener un modificador para' s /// 'que le indique que haga una copia de la cadena, (posiblemente) modificar la copia y devolver esa nueva cadena. Creo que he visto eso sugerido antes, pero aún no ha llegado a Perl, y es posible que nunca se agregue. – cjm

-1

Hay otra manera: escribir su propia función:

sub replace (
    my $variable = shift; 
    my $substring = shift; 

    eval "\$variable =~ s${substring};"; 
    return $variable 
} 

doStuff(replace($foo, "/regex/replace/")); 

Ésta no sería la pena para una sola llamada, y sería probablemente sólo hacer que el código sea más confuso en ese caso. Sin embargo, si lo hace una docena de veces, puede tener más sentido escribir su propia función para hacer esto.

5
use Algorithm::Loops "Filter"; 

# leaves $foo unchanged 
doStuff(Filter { s/this/that/ } $foo); 
+0

'List :: MoreUtils' tiene la misma función llamada' apply' que probablemente sea un nombre mejor para ella. 'Filter' me hace pensar en la funcionalidad de tipo' grep' (probablemente porque 'grep' se llama' filter' en la mayoría de los lenguajes). –

Cuestiones relacionadas