2011-05-21 16 views
25

Tengo un pequeño problema para comprender este uso simple del modificador/e regex.Modificador de Perl Regex 'e' (eval) con s ///

my $var = 'testing'; 
$_ = 'In this string we are $var the "e" modifier.'; 

s/(\$\w+)/$1/ee; 

print; 

Devoluciones: "En esta cadena estamos probando el modificador" e ".

No veo por qué se requieren dos modificadores 'e'. Por lo que puedo ver, $ 1 debe capturar '$ var' de la cadena y un modificador 'e' debería poder reemplazar la variable con su valor. Sin embargo, debo estar malinterpretando algo, ya que probar el código anterior con solo un modificador 'e' no reemplaza visiblemente nada en la cadena.

Disculpe por hacer una pregunta tan simple!

Gracias.

+4

nota que "e" no es un modificador de expresiones regulares, ya que no afecta a la expresión regular! Solo afecta la parte de reemplazo. Entonces "e" modifica el operador s ///, no la expresión regular. – tadmc

Respuesta

36

No es exactamente una pregunta "simple", así que no te rindas.

El problema es que con un solo /e, se entiende que el RHS es un código cuyo resultado eval 'd se utiliza para el reemplazo.

¿Qué es eso RHS? Es $1. Si evaluó $1, encontrará que contiene la cadena$var. No contiene el contenido de dicha variable, solo $ seguido de v seguido de a seguido de r.

Por lo tanto debe evaluar dos veces, una vez para encender $1 en $var, a continuación, de nuevo para activar el resultado anterior de $var en la cadena "testing". Lo haces teniendo el modificador doble ee en el s operator.

Puede comprobar esto bastante fácilmente ejecutándolo con un /e frente a dos de ellos. Aquí hay una demostración de ambos, más una tercera vía que usa eliminación de referencias simbólica, que, debido a que hace referencia a la tabla de símbolos del paquete, solo funciona en variables de paquete.

use v5.10; 

our $str = q(In this string we are $var the "e" modifier.); 
our $var = q(testing); 

V1: { 
    local $_ = $str; 
    s/(\$\w+)/$1/e; 
    say "version 1: ", $_; 

} 

V2: { 
    local $_ = $str; 
    s/(\$\w+)/$1/ee; 
    say "version 2: ", $_; 
} 

V3: { 
    no strict "refs"; 
    local $_ = $str; 
    s/\$(\w+)/$$1/e; 
    say "version 3: ", $_; 
} 

Cuando se ejecuta, que produce:

version 1: In this string we are $var the "e" modifier. 
version 2: In this string we are testing the "e" modifier. 
version 3: In this string we are testing the "e" modifier. 
+0

Eso es genial, gracias. Como curiosidad, ¿por qué la producción de la expresión regular s/(\ $ \ w +)/$ 1/sin el modificador todavía la reemplaza con el valor capturado ($ var)? Me parece que eso es para lo que está el primero/e? – Pete171

+2

@ user761513: sin ningún modificador, '$ 1' como texto de reemplazo se utiliza como una cadena. Con una sola 'e', ​​se usa como una expresión, con exactamente el mismo resultado. Para ver la diferencia, compare 's/.../$ 1 (hello) /' (una cadena) con 's/.../uc ($ 1)/e' (una expresión). – Gilles

+1

Específicamente, sin ningún modificador, el texto de reemplazo actúa como una cadena _double citado_. Por lo tanto, '$ 1' se interpola a lo que fue capturado por el primer conjunto de paréntesis. – pjf

6

Para ser claros, la forma s//ee no tiene previsto modificar su patrón de expresión o interpretación de expresiones regulares en absoluto. Es un tratamiento opcional de la cadena lateral de reemplazo después de realizar la expresión regular. (Ver PERLOP Regex Quote-like operators)

El e o ee simplemente se mezclan en las opciones de expresiones regulares secundarios patrón en forma s/PATTERN/REPLACEMENT/msixpodualgcer.

De Perlop:

opciones son las m // con la adición de las siguientes opciones específicas de reemplazo :

e Evaluate the right side as an expression. 
ee Evaluate the right side as a string then eval the result. 
r Return substitution and leave the original string untouched. 

Se puede ver el mismo tipo de e vs ee comportamiento en situaciones no regex, como muestra este ejemplo:

#!/usr/bin/perl 
use warnings; 
use strict; 

my $var = "var's contents"; 
my $str='"-> $var <-"'; 
print eval('$str'), "\n";  # equivalent to s//e 
print eval(eval('$str')), "\n"; # equivalent to s//ee 

Salida:

"-> $var <-" 
-> var's contents <- 
+1

¿Qué hace '# use strinct'? ; -} – dawg

+1

@drewk: '# use strinct do?' Le dice al mundo que no puedo deletrear ... error tipográfico ... –

+0

[Rechazado como una edición] Una nota final, solo por completitud: puede agregar incluso más 'e's, no es porque la documentación se detenga allí que no es factible: my $ testing = '¡Uf!'; my $ var = '$ testing'; $ _ = 'Estamos $ var el modificador "e".'; s/(\ $ \ w +)/$ 1/e; imprimir; $ _ = 'Estamos $ var el modificador "e".'; s/(\ $ \ w +)/$ 1/ee; imprimir; $ _ = 'Estamos $ var el modificador "e".'; s/(\ $ \ w +)/$ 1/eee; imprimir; produciendo Estamos $ var el modificador "e". Estamos $ probando el modificador "e". Somos Phew! el modificador "e". – OmarOthman

0

Pruebe la utilidad de cambio de nombre del último paquete de Perl con:

rename -v 's/\b(\w)/uc($1)/eg' * 

Aquí, el patrón \b encontrar el límite de palabra, y el modificador e permite la evaluación de la sustitución, y g reemplazan todas las ocurrencias.

También puede cambiar el nombre a camelCase con:

rename -v 's/\b(\w)/uc($1)/eg' * 
rename -v 's/^(\w)/lc($1)/e' * 
rename -v 's/\s+//g' * 
Cuestiones relacionadas