2010-07-13 19 views
5

¿Hay alguna manera de usar una variable como modificador en una sustitución?Cómo usar una variable como modificador en una sustitución

my $search = 'looking'; 
my $replace = '"find: $1 ="'; 
my $modifier = 'ee'; 

s/$search/$replace/$modifier; 

Necesito usar una matriz de valores hash para realizar la búsqueda masiva-reemplazar con diferentes modificadores.

+9

Algunos modificadores se pueden suministrar dentro de la expresión regular como '(? Modificador: patrón)' pero no son cosas que afectan todo como/g o/e. Este es uno de esos momentos de "por qué estás haciendo eso". Si nos dijiste para qué sirve, podríamos encontrar una forma más sencilla en lugar de cepillarnos el pelo de camello (y abrir un agujero de seguridad). – Schwern

+0

@Schwern: Y es muy desagradable si abres un agujero en tu camello – Borodin

Respuesta

3

Hm, si tuviera que hacerlo lo haría así:

use warnings; 
use strict; 
my @stuff = (
{ 
    search => "this", 
    replace => "that", 
    modifier => "g", 
}, 
{ 
    search => "ono", 
    replace => "wendy", 
    modifier => "i", 
} 
); 
$_ = "this ono boo this\n"; 
for my $h (@stuff) { 
    if ($h->{modifier} eq 'g') { 
     s/$h->{search}/$h->{replace}/g; 
    } elsif ($h->{modifier} eq 'i') { 
     s/$h->{search}/$h->{replace}/i; 
    } 
    # etc. 
} 
print; 

Sólo hay tantos modificadores diferentes es posible que desee utilizar así que creo que esta es bastante fácil

Puede usar eval para esto, pero es terriblemente desordenado.

+7

Desordenado está en el ojo del espectador. Encuentro esto más complicado que la solución de evaluación. – runrig

+2

@runrig: "desordenado" en este caso no se refiere a cómo se ve el código. Hay muchos errores difíciles de rastrear de los que debe ocuparse si usa 'eval'. –

+0

Esta es la solución en la que estaba pensando antes de preguntar Stackoverflox. – bem33

4

Puede usar eval, si se pone sus gafas de seguridad y su traje dividido por cero.

Ej:

use strict; 
use warnings; 
sub mk_re { 
    my ($search, $replace, $modifier) = @_; 
    $modifier ||= ''; 
    die "Bad modifier $modifier" unless $modifier =~ /^[msixge]*$/; 
    my $sub = eval "sub { s/($search)/$replace/$modifier; }"; 
    die "Error making regex for [$search][$replace][$modifier]: [email protected]" unless $sub; 
    return $sub; 
} 

my $search = 'looking'; 
my $replace = '"find: $1 ="'; 
my $modifier = 'e'; 

# Sub can be stored in an array or hash 
my $sub = mk_re($search, $replace, $modifier); 

$_ = "abc-looking-def"; 
print "$_\n"; 
$sub->(); 
print "$_\n"; 
+0

Mi traje dividido por cero tiene un agujero alrededor de menos infinito – Borodin

4

Si bien el método que utiliza eval compilar un nuevo sustitución es probablemente el más sencillo, se puede crear una sustitución que es más modular:

use warnings; 
use strict; 

sub subst { 
    my ($search, $replace, $mod) = @_; 

    if (my $eval = $mod =~ s/e//g) { 
     $replace = qq{'$replace'}; 
     $replace = "eval($replace)" for 1 .. $eval; 
    } else { 
     $replace = qq{"$replace"}; 
    } 
    sub {s/(?$mod)$search/$replace/ee} 
} 

my $sub = subst '(abc)', 'uc $1', 'ise'; 

local $_ = "my Abc string"; 

$sub->(); 

print "$_\n"; # prints "my ABC string" 

Esto sólo se prueba la ligera, y se deja como un ejercicio para que el lector implemente otros indicadores como g

+0

+1 Inteligente, siempre que se tomen precauciones de seguridad ... – dawg

+0

Parece ser una buena manera. Le echaré un vistazo. Gracias. – bem33

+0

¿Por qué tener un modificador 'ee' en cada sustitución? – runrig

2

Por supuesto, s/$search/$replace/ funcionan según lo previsto. Son los modificadores dinámicos que no son directos.

Para la coincidencia normal modifiers de pimsx puede usar Extended Patterns de Perl para modificar los indicadores de modificación sobre la marcha como parte de su patrón. Estos tienen el formato (?pimsx-imsx) para activar/desactivar esos modificadores.

Para los s//e y ee formas, puede utilizar (?{ perl code}) documentado en la misma sección perlre. Para todos los formularios evale o ee, ¡tenga en cuenta la seguridad del código resultante!

No hay ninguna forma de modificar global para la primera coincidencia que conozco, por lo que global vs first match necesitaría ser declaraciones separadas.

2

Aquí hay una combinación de la respuesta y evaluación de Kinopiko.

eval se usa aquí para generar la tabla de búsqueda de una manera controlada y mantenible, y una tabla de búsqueda se usa para guardar todos los if .. elsif .. elsif que no son muy divertidos de ver.

(muy ligeramente a prueba)

my @stuff = (
{ 
    search => "this", 
    replace => "that", 
    modifier => "g", 
}, 
{ 
    search => "ono", 
    replace => "wendy", 
    modifier => "i", 
} 
); 
$_ = "this ono boo this\n"; 

my @modifiers = qw{m s i x g e}; 

my $s_lookup = {}; 

foreach my $modifier (@modifiers) { 
    $s_lookup->{$modifier} = eval " sub { s/\$_[0]/\$_[1]/$modifier } "; 
} 

for my $h (@stuff) { 
    $s_lookup->{$h->{modifier}}->($h->{search},$h->{replace}); 
} 

print; 

Para ser totalmente útil esta necesita:

  1. combinaciones de posibles modificadores
  2. función
  3. tipo en la tabla de consulta de modo combinación 'msi' y 'MIS 'combinación irá a la misma clave.
+0

O simplemente agregue una verificación de validación de modificador a la otra respuesta de evaluación, como la que hay ahora. – runrig

Cuestiones relacionadas