2010-01-04 3 views
10

Angenommen, ich habe eine Datei mit Zeilen Ich versuche gegen entsprechen:Wie kann ich Metazeichen entschlüsseln, wenn ich eine Variable in Perls Matchoperator interpoliere?

foo 
quux 
bar 

In meinem Code, habe ich ein anderes Array:

foo 
baz 
quux 

Lassen Sie uns sagen, dass wir durch die Datei iterieren, jeder Aufruf Element $word, und die interne Liste, die wir gegen überprüfen, @arr.

if(grep {$_ =~ m/^$word$/i} @arr) 

Dies funktioniert korrekt, aber in dem etwas möglich Fall, in dem wir einen Testfall fo. in der Datei haben, die . arbeitet als Wildcard-Operator in der Regex und fo. paßt dann foo, was nicht akzeptabel ist .

Dies ist natürlich, weil Perl die Variable in eine Regex interpoliert.

Die Frage:

Wie kann ich Perl zwingen wahrsten Sinne des Wortes um die Variable zu benutzen?

+0

Siehe http://stackoverflow.com/questions/1949731/how-can-i-escape-a-literal-string-i- interpolieren in einen regulären Ausdruck –

+1

mögliches Duplikat von [Wie handle ich Sonderzeichen in einer Perl-Regex?] (http://stackoverflow.com/questions/576435/how-do-i-handle -special-characters-in-a-per-regex) – daxim

Antwort

5

quotemeta

Gibt den Wert von EXPR mit allen nicht "Wort" Zeichen backslashed. Verwenden Sie nicht regexps -

if(grep {$_ =~ m/^\Q$word\E$/i} @arr) 
30

Verwenden \Q...\E spezielle Symbole direkt in Perl-String nach Variablenwert Interpolation zu entkommen. Ich sage nicht, dass Regexps schlecht sind, aber sie für (was gleichbedeutend ist) einfache Gleichheitsprüfung zu verwenden, ist Overkill.

Verwenden Sie: grep { lc($_) eq lc($word) } @arr und glücklich sein.

+0

Was ist wenn '$ word =' ​​fo \ E.''? –

+0

Dann wird regexp etwas wie "m/^ f \\ E \. $/I" sein. Siehe '\ Q' Meta-Symbol Beschreibung auf http://perldoc.perl.org/perlfaq6.html –

+0

Insbesondere, http://perldoc.perl.org/perlop.html#Quote-and-Quote-like-Operators Notizen dass "abc \ Qfoo \ tbar $ s \ Exyz" 'äquivalent zu" "abc" ist. Zitat ("foo \ tbar $ s"). "xyz" '. –

15

Von perlfaq6 ‚s Antwort auf How do I match a regular expression that's in a variable?:


Wir haben nicht zu hart Codemuster in den Match-Operator (oder irgendetwas anderes, das mit regulären Ausdrücken arbeitet). Wir können das Muster zur späteren Verwendung in eine Variable einfügen.

Der Übereinstimmungsoperator ist ein doppelter Anführungszeichenkontext, so dass Sie Ihre Variable wie eine doppelte Anführungszeichenfolge interpolieren können. In diesem Fall lesen Sie den regulären Ausdruck als Benutzereingabe und speichern ihn in $ regex. Sobald Sie das Muster in $ regex haben, verwenden Sie diese Variable im Match-Operator.

chomp(my $regex = <STDIN>); 

if($string =~ m/$regex/) { ... } 

Alle regulären Ausdruck Sonderzeichen in $ regex sind noch besondere, und das Muster immer noch gültig sein oder Perl wird sich beschweren. Zum Beispiel gibt es in diesem Muster eine ungepaarte Klammer.

Wenn Perl den regulären Ausdruck kompiliert, behandelt es die Klammer als den Beginn einer Speicherübereinstimmung.Wenn es nicht die schließende Klammer finden, es klagt:

Unmatched (in regex; marked by <-- HERE in m/Unmatched (<-- HERE paren/ at script line 3. 

Sie, um dies auf verschiedene Weise erhalten Sie auf unserer Situation abhängig. Erstens, wenn Sie nicht möchten, dass eines der Zeichen in der Zeichenfolge speziell ist, können Sie sie mit quitemeta vor der Verwendung der Zeichenfolge umgehen.

Sie können dies auch direkt im Match-Operator mit den Sequenzen \ Q und \ E tun. Das \ Q teilt Perl mit, wo Sonderzeichen zu entkommen sind, und das \ E sagt ihm, wo es anhalten soll (siehe Perl für weitere Details).

Alternativ können Sie qr //, den regulären Ausdruck-Anführungsoperator verwenden (siehe perlop für weitere Details). Es zitiert und vielleicht kompiliert das Muster, und Sie können Flags für reguläre Ausdrücke auf das Muster anwenden.

Sie könnten auch Fehler abfangen wollen, indem Sie einen Eval-Block um das Ganze wickeln.

chomp(my $input = <STDIN>); 

eval { 
    if($string =~ m/\Q$input\E/) { ... } 
    }; 
warn [email protected] if [email protected]; 

Oder ...

my $regex = eval { qr/$input/is }; 
if(defined $regex) { 
    $string =~ m/$regex/; 
    } 
else { 
    warn [email protected]; 
    } 
+0

Ist das Eval im vorletzten Codebeispiel, um Fehler in "{...}" zu fangen oder könnte auch etwas in "if ($ string = ~ m/\ Q $ input \ E /)" falsch sein? –

+0

Das Eval fängt alle Fehler in seinem Block ab, aber in Bezug auf diese Frage wird ein Fehler im expliziten Code im Match-Operator festgestellt. –

2

Ich glaube nicht, dass Sie einen regulären Ausdruck in diesem Fall wollen, da Sie nicht mit einem Muster übereinstimmen. Sie suchen nach einer wörtlichen Zeichenfolge, die Sie bereits kennen. Erstellen Sie eine Hash mit den Werten übereinstimmen und verwenden filtern @arr:

open my $fh, '<', $filename or die "..."; 
my %hash = map { chomp; lc($_), 1 } <$fh>; 

foreach my $item (@arr) 
     { 
     next unless exists $hash{ lc($item) }; 
     print "I matched [$item]\n"; 
     } 
Verwandte Themen