2009-08-03 10 views
6

Piszę malutki program, który pobiera dane użytkownika za pomocą Getops, i na jego podstawie program spróbuje dopasować wzór do jakiegoś tekstu lub zastąpić tekst tym, co pasuje.Perl qr // i podstawienie

Problem polega na tym, że nie mogę uruchomić części zastępczej. Patrzę na wpis qr // na stronach man: http://perldoc.perl.org/perlop.html#Regexp-Quote-Like-Operators, ale nie mam z tym szczęścia. Próbowałem modelować mój kod dokładnie tak, jak dokumenty w tym przypadku. Kompiluję wzór dopasowania i zastępuję go zamiennikiem.

Czy ktoś może wskazać, gdzie się źle wybieram? (Nie martw się o bezpieczeństwo zbyt dużo, to tylko mały skrypt do użytku osobistego)

Oto czego szukam w:

if($options{r}){ 

    my $pattern = $options{r}; 
    print "\nEnter Replacement text: "; 
    my $rep_text = <STDIN>; 

    #variable grab, add flags to pattern if they exist. 
    $pattern .= 'g' if $options{g}; 
    $pattern .= 'i' if $options{i}; 
    $pattern .= 's' if $options{s}; 


    #compile that stuff 
    my $compd_pattern = qr"$pattern" or die [email protected]; 
    print $compd_pattern; #debugging 

    print "Please enter the text you wish to run the pattern on: "; 
    my $text = <STDIN>; 
    chomp $text;  

    #do work and display 
    if($text =~ s/$compd_pattern/$rep_text/){ #if the text matched or whatever 
     print $text; 
    } 
    else{ 
     print "$compd_pattern on \n\t{$text} Failed. "; 
    } 
} #end R FLAG 

Kiedy uruchamiam go z -r „/ mat/"-i, i wprowadź tekst zastępczy" matthew ", na tekście" matowy ", to się nie powiedzie. Dlaczego to?

EDYTOWANIE:

Dzięki za odpowiedzi chłopaki! To było naprawdę bardzo pomocne. Połączyłem obie twoje sugestie w działające rozwiązanie tego problemu. Muszę obsługiwać flagę/g trochę inaczej. Oto próbka robocza:

if($options{r}){ 

    my $pattern = $options{r}; 
    print "\nEnter Replacement text: "; 
    my $rep_text = <STDIN>; 
    chomp $rep_text; 

    #variable grab, add flags to pattern if they exist. 

    my $pattern_flags .= 'i' if $options{i}; 
    $pattern_flags .= 's' if $options{s}; 

    print "Please enter the text you wish to run the pattern on: "; 
    my $text = <STDIN>; 
    chomp $text;  

    #do work and display 
    if($options{g}){ 
     if($text =~ s/(?$pattern_flags:$pattern)/$rep_text/g){ #if the text matched or whatever (with the g flag) 
      print $text; 
     } 
     else{ 
      print "$pattern on \n\t{$text} Failed. "; 
     } 
    } 
    else{ 
     if($text =~ s/(?$pattern_flags:$pattern)/$rep_text/){ #if the text matched or whatever 
      print $text; 
     } 
     else{ 
      print "$pattern on \n\t{$text} Failed. "; 
     } 
    } 
} #end R FLAG 

Odpowiedz

11

Jak wskazuje chaos, napotkasz pewne trudności używając qr//. Czy naprawdę potrzebujesz prekompilować wzór? Jeśli nie, to strategia jak to może działać:

my $pattern  = 'matt'; 
my $text   = 'Matt'; 
my $rep_text  = 'Matthew'; 
my $pattern_opts = 'i'; 

print $text, "\n" if $text =~ s/(?$pattern_opts:$pattern)/$rep_text/; 

aktualizacji w odpowiedzi na nowy kod: można rozważyć zastosowanie podejścia takiego:

my ($orig, $patt, $rep, $flags) = qw(FooFooFoo foo bar ig); 

my $make_replacement = $flags =~ s/g//  ? 
    sub { $_[0] =~ s/(?$flags:$patt)/$rep/g } : 
    sub { $_[0] =~ s/(?$flags:$patt)/$rep/ } 
; 

if ($make_replacement->($orig)){ 
    print $orig; 
} 
else { 
    print "Failed..."; 
} 
+0

Ahh, bardzo dobre z '(? opts: pat) '. Zawsze zapominam, że możesz to zrobić. – chaos

7

uruchomić go z -r "matt", nie -r "/matt/". Nie musisz, a właściwie nie możesz, podać ograniczników wzorca w ciągu opcji. Cytaty są ogranicznikami w twoim qr. Tak naprawdę szukają matt z ukośnikami wokół niej, sposobem, w jaki ją uruchamiasz, co nie jest tym, czego potrzebujesz. Próbujesz użyć tych cytatów, aby powiedzieć Perlowi, aby traktował twój ciąg wzorców tak, jakby był to kod źródłowy, ale niestety nie możesz tego zrobić.

Wszystkie te wzory elementów, które robisz dla innych opcji, również nie będą działać. Będziesz musiał zmienić sposób kompilacji wyrażenia regularnego, jeśli chcesz to wszystko zrobić. Coś takiego może zrobić dla /i i /s:

my $compd_pattern = qr/$pattern/ or die [email protected]; 
$compd_pattern = qr/$compd_pattern/i if $options{i}; 
$compd_pattern = qr/$compd_pattern/s if $options{s}; 

Dla /g trzeba wspierać alternatywną wersję poszukiwania/wymienić. /g nie jest poprawnym modyfikatorem do qr//.