2009-01-22 5 views
6

In Python kompiliert regex Muster have a findall method, die die folgenden:Gibt es ein Perl-Äquivalent von Pythons re.findall/re.finditer (iterative Regex-Ergebnisse)?

Zurück alle nicht-überlappende Spiele von Muster in String, als eine Liste von Saiten. Die Zeichenfolge wird von links nach rechts durchsucht , und Übereinstimmungen werden zurückgegeben in der Reihenfolge gefunden. Wenn eine oder weitere Gruppen im Muster vorhanden sind, geben Sie eine Liste der Gruppen zurück. Diese wird eine Liste von Tupeln sein, wenn das Muster mehr als eine Gruppe hat. Leere Treffer sind im Ergebnis enthalten , es sei denn, sie berühren den Anfang von ein anderes Spiel.

Was ist die kanonische Art, dies in Perl zu tun? Ein naive Algorithmus, den ich mir vorstellen kann, ist wie folgt: "Während ein Suchen und Ersetzen durch die leere Zeichenfolge erfolgreich ist, mache [suite]". Ich hoffe, es gibt einen schöneren Weg. :-)

Vielen Dank im Voraus!

Antwort

13

Verwenden Sie den Modifikator /g in Ihrer Übereinstimmung. Vom perlop Handbuch:

Der „/g“ Modifikator globalen Pattern-Matching gibt - das heißt, so oft wie möglich innerhalb der String-Matching. Wie es sich verhält, hängt vom Kontext ab. Im Listenkontext wird eine Liste der Teilzeichenfolgen zurückgegeben, die mit allen auffindbaren Klammern im regulären Ausdruck übereinstimmen. Wenn keine Klammern vorhanden sind, wird eine Liste aller übereinstimmenden Zeichenfolgen zurückgegeben, als ob um das gesamte Muster herum Klammern vorhanden wären.

Im skalaren Kontext findet jede Ausführung von "m//g" die nächste Übereinstimmung und gibt true zurück, wenn sie übereinstimmt, und false, wenn keine weitere Übereinstimmung besteht. Die Position nach der letzten Übereinstimmung kann mit der Funktion pos() gelesen oder eingestellt werden; siehe "pos" in perlfunc. Eine fehlgeschlagene Übereinstimmung setzt die Suchposition normalerweise auf den Anfang der Zeichenfolge zurück, aber Sie können dies vermeiden, indem Sie den Modifikator "/c" hinzufügen (z. B. "m//gc"). Durch Ändern der Zielzeichenfolge wird auch die Suchposition zurückgesetzt.

+0

D'oh - natürlich! Ich hätte das aus Vim Land erfahren sollen. – cdleary

7

auf Antwort Chris zu bauen, ist es wahrscheinlich am wichtigsten die //g Regex in einer while Schleife umhüllen, wie:

my @matches; 
while ('foobarbaz' =~ m/([aeiou])/g) 
{ 
    push @matches, $1; 
} 

Einfügen einig schnellen Python I/O:

>>> import re 
>>> re.findall(r'([aeiou])([nrs])','I had a sandwich for lunch') 
[('a', 'n'), ('o', 'r'), ('u', 'n')] 

Um etwas vergleichbar in Perl zu bekommen, könnte das Konstrukt etwas wie sein:

my $matches = []; 
while ('I had a sandwich for lunch' =~ m/([aeiou])([nrs])/g) 
{ 
    push @$matches, [$1,$2]; 
} 

Aber im Allgemeinen, was auch immer Funktion Sie Iterieren, können Sie wahrscheinlich innerhalb der while Schleife selbst tun.

+1

Aber was ist mit '@matches = 'Ich hatte ein Sandwich zum Mittagessen' = ~ m/([aeiou]) ([nrs])/g'? Sicher, du bekommst ein flaches Array, aber dann kannst du es (in diesem Fall) pro Stück spleißen. :-) –

+0

Ah-hm. Die Schönheit von Perl ist, dass es immer einen anderen Weg gibt! Ich bin froh, dass ich gesagt habe, "könnte so etwas wie sein" :) – kyle