2012-04-08 7 views
1

Ich habe eine Liste von Mustern, die ich in einer Zeichenfolge suchen möchte. Diese Muster sind zahlreich und enthalten zahlreiche Metazeichen, die ich nur wörtlich zuordnen möchte. Dies ist also die perfekte Anwendung für Metaquoting mit \Q..\E. Die Komplikation besteht darin, dass ich der Variablenliste von Mustern einen regulären Ausdruck zuordnen muss.Metaquoting Muster in einer Variablenliste

use strict; 
use warnings; 
# sample string to represent my problem 
    my $string = "{{a|!}} Abra\n{{b|!!}} {{b}} Hocus {{s|?}} Kedabra\n{{b|+?}} {{b|??}} Pocus\n {{s|?}}Alakazam\n"; 

# sample patterns to look for  
my @patterns = qw({{a|!}} {{s|?}} {{s|+?}} {{b|?}}); 
# since these patterns can be anything, I join the resulting array into a variable-length regex 
my $regex = join("|",@patterns); 

my @matched = $string =~ /$regex(\s\w+\s)/; # Error in matching regex due to unquoted metacharacters 
print join("", @matched); # intended result: Hocus\n Pocus\n 

Als ich metaquoting in den Verbindungsvorgang einzuführen versuchen, scheinen sie keine Wirkung zu haben.

Aus irgendeinem Grund hat das Metaquoting keine Auswirkungen, wenn es in der Zeichenfolge enthalten ist, die ich als regulären Ausdruck verwende. Für mich funktionieren sie nur, wenn sie direkt zu einer Regex wie in /\Q$anexpression\E/ hinzugefügt werden, aber soweit ich sagen kann, ist dies keine Option für mich. Wie komme ich hier zurecht?

Antwort

1

Ich verstehe Ihr erwartetes Ergebnis nicht, da Abra und Kedabra die einzigen Strings sind, denen eines der Muster vorausgeht.

Ihr Problem lösen Sie jede Komponente der Regex separat als \Q und \E wirken sich nur auf den Wert der Zeichenfolge, in der sie erscheinen, so "\Q" und "\E" sind nur die Null-String "" und "\E|\Q" ist nur "|" entkommen muss. Sie könnten schreiben

my $qmregex = join '|', map "\Q$_\E", @patterns; 

aber es ist einfacher, die quotemeta Funktion aufzurufen.

Sie müssen auch die Liste in Klammern (?:...) einschließen, um den Wechsel zu isolieren und den Modifikator /g auf die Regex-Übereinstimmung anwenden, um alle Ereignisse in der Zeichenfolge zu finden. Versuchen

use strict; 
use warnings; 

my $string = "{{a|!}} Abra\n{{b|!!}} {{b}} Hocus {{s|?}} Kedabra\n{{b|+?}} {{b|??}} Pocus\n {{s|?}}Alakazam\n"; 

my @patterns = qw( {{a|!}} {{s|?}} {{s|+?}} {{b|?}} ); 

my $regex = join '|', map quotemeta, @patterns; 
my @matched = $string =~ /(?:$regex)(\s\w+\s)/g; 
print @matched; 

Ausgang

Abra 
Kedabra