2010-07-13 18 views
5

Esiste un modo per utilizzare una variabile come modificatore in una sostituzione?Come utilizzare una variabile come modificatore in una sostituzione

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

s/$search/$replace/$modifier; 

Ho bisogno di utilizzare una matrice di hash per rendere la ricerca di massa-sostituzione con diversi modificatori.

+9

Alcuni modificatori possono essere forniti all'interno della regex come '(? Modifier: pattern)' ma non cose che influenzano l'intera cosa come/g o/e. Questo è uno di quei momenti "perché stai facendo questo". Se ci hai detto a cosa serve, potremmo essere in grado di trovare un modo più semplice piuttosto che sfiorare i capelli di cammello (e aprire un buco di sicurezza). – Schwern

+0

@Schwern: Ed è molto spiacevole se apri un buco nel tuo cammello – Borodin

risposta

3

Hm, se dovessi farlo lo farei in questo modo:

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; 

Ci sono solo così tanti modificatori differenti si potrebbe desiderare di utilizzare quindi penso che questo è abbastanza facile.

È possibile utilizzare eval per questo, ma è terribilmente disordinato.

+7

Messy è negli occhi di chi guarda. Trovo questo più messico della soluzione eval. – runrig

+2

@runrig: "disordinato" in questo caso non si riferisce a come appare il codice. Ci sono molti bug difficili da rintracciare che devi prendere in considerazione se usi 'eval'. –

+0

Questa è la soluzione a cui stavo pensando prima di chiedere Stackoverflox. – bem33

4

È possibile utilizzare eval, se si indossano gli occhiali di protezione e la tuta divisi per zero.

Esempio:

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

Il mio vestito diviso per zero ha un buco attorno al meno infinito – Borodin

4

Mentre il metodo che utilizza eval per compilare una nuova sostituzione è probabilmente il più semplice, è possibile creare una sostituzione che è più modulare:

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" 

Questo è solo leggermente testato, e si lascia come un esercizio per il lettore implementare altre bandiere come g

+0

+1 Intelligente, purché siano prese precauzioni di sicurezza ... – dawg

+0

Sembra essere un buon modo. Darò un'occhiata. Grazie. – bem33

+0

Perché avere un modificatore 'ee' su ogni sostituzione? – runrig

2

Ovviamente s/$search/$replace/ funziona come previsto. Sono i modificatori dinamici che non sono diretti.

Per la corrispondenza regolare modifiers di pimsx è possibile utilizzare Perl Extended Patterns per modificare i flag di modifica al volo come parte del modello. Questi sono nella forma (?pimsx-imsx) per attivare/disattivare quei modificatori.

Per i s//e e ee moduli, è possibile utilizzare (?{ perl code}) documentato nella stessa sezione perlre. Per tutti i moduli evale o ee, considerare la sicurezza del codice risultante!

Non esiste alcun modo per modificare la corrispondenza globale con la prima nota di cui sono a conoscenza, quindi la corrispondenza globale e quella prima devono essere dichiarazioni separate.

2

Ecco una combinazione di risposta e valutazione di Kinopiko.

eval è qui utilizzato per generare la tabella di ricerca in modo controllato e sostenibile, e una tabella di ricerca viene utilizzato per salvare tutti i se .. elsif .. elsif che non sono troppo divertente da guardare.

(molto leggermente testato)

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; 

essere pienamente utile questo deve:

  1. combinazioni di possibili modificatori
  2. funzione
  3. sorta sulla tabella di ricerca così combinazione 'MSI' e 'mis 'la combinazione andrà alla stessa chiave.
+0

Oppure basta aggiungere un controllo di validazione del modificatore all'altra risposta eval come quella presente ora. – runrig