So passen Sie alle Vorkommen eines regulären Ausdrucks an
586
Gibt es eine schnelle Möglichkeit, jede Übereinstimmung eines regulären Ausdrucks in Ruby zu finden? Ich habe das Regex-Objekt in der Ruby STL durchsucht und vergeblich bei Google gesucht.
Aber was ist mit diesem Fall? "pass zu mir!". scan (/.../) = ["mat", "ch" "me!" ], aber alle Vorkommen von /.../ wären ["mat", "atc", "tch", "ch", ...]
Michael Dickens
13
Nicht wäre es nicht. /.../ ist ein normaler gieriger regulärer Ausdruck. Übereinstimmende Inhalte werden nicht zurückverfolgt. Sie könnten versuchen, einen faulen regulären Ausdruck zu verwenden, aber selbst das wird wahrscheinlich nicht ausreichen. Schauen Sie sich das Regexp-Dokument ruby-doc.org/core-1.9.3/Regexp.html an, um Ihr Regexp korrekt auszudrücken :)
Jean
49
Dies scheint wie eine Ruby WTF ... warum ist dies auf String anstelle von Regexp mit den anderen Regexp-Sachen? Es wird nicht einmal irgendwo in den Dokumenten für Regexp
Anentropic
9
Ich denke, das liegt daran, dass es für String definiert und aufgerufen wird, nicht für Regex ... Aber es macht tatsächlich Sinn. Sie können einen regulären Ausdruck schreiben, um alle Übereinstimmungen mit Regex # match zu erfassen und über erfasste Gruppen zu iterieren. Hier schreiben Sie eine Teilübereinstimmungsfunktion und möchten, dass sie mehrmals auf eine bestimmte Zeichenfolge angewendet wird. Dies liegt nicht in der Verantwortung von Regexp. Ich schlage vor, Sie überprüfen die Implementierung des Scans für ein besseres Verständnis: ruby-doc.org/core-1.9.3/String.html#method-i-scan
Jean
9
@ MichaelDickens: In diesem Fall können Sie verwenden /(?=(...))/.
Konrad Borowski
67
Verwenden Sie die String- scanMethode, um alle übereinstimmenden Zeichenfolgen zu finden .
Vielleicht hast du falsch verstanden. Der reguläre Ausdruck des Beispiels eines Benutzers, auf den ich geantwortet habe, war: /(\d+)[m-t]/Nicht /\d+[m-t]/schreiben: re = /(\d+)[m-t]/; str.scan(re)ist derselbe, str.scan(/(\d+)[mt]/)aber ich erhalte #> [["" 54 "], [" 1 "], [" 3 "]]und nicht "54m", "1t", "3r"]Die Frage war: Wenn ich einen regulären Ausdruck mit einer Gruppe habe und alle Muster erfassen möchte, ohne den regulären zu ändern Ausdruck (Verlassen der Gruppe), wie kann ich das machen? In diesem Sinne war eine mögliche Lösung, wenn auch etwas kryptisch und schwer zu lesen ,:str.to_enum(:scan,re).map {$&}
MVP
-1
Sie können verwenden string.scan(your_regex).flatten. Wenn Ihre Regex Gruppen enthält, wird sie in einem einzelnen einfachen Array zurückgegeben.
Entfernen Sie die Gruppierung aus your_regex = /(\d+)[m-t]/und Sie müssen sie nicht verwenden flatten. Ihr letztes Beispiel verwendet, last_matchwas in diesem Fall wahrscheinlich sicher ist, aber global ist und möglicherweise überschrieben werden könnte, wenn vor dem Aufruf ein regulärer Ausdruck gefunden wurdelast_match . Stattdessen ist es wahrscheinlich sicherer zu verwenden string.match(regex).captures # => ["group_photo", "jpg"]oder string.scan(/\d+/) # => ["54", "3", "1", "7", "3", "0"]wie in anderen Antworten gezeigt, je nach Muster und Anforderungen.
Antworten:
Verwenden
scan
sollte den Trick tun:quelle
/(?=(...))/
.Verwenden Sie die String-
scan
Methode, um alle übereinstimmenden Zeichenfolgen zu finden .Wenn Sie möchten,
MatchData
welchen Typ das von der Regexp-match
Methode zurückgegebene Objekt hat , verwenden Sie:Der Vorteil der Verwendung
MatchData
besteht darin, dass Sie Methoden wie dieoffset
folgenden verwenden können :Sehen Sie sich diese Fragen an, wenn Sie mehr wissen möchten:
Lesen Sie weiter über spezielle Variablen
$&
,$'
,$1
,$2
in Ruby wird auch hilfreich sein.quelle
Wenn Sie einen regulären Ausdruck mit Gruppen haben:
Sie können die String-
scan
Methode verwenden, um übereinstimmende Gruppen zu finden:So finden Sie das passende Muster:
quelle
str.scan(/\d+[m-t]/) # => ["54m", "1t", "3r"]
ist idiomatischer alsstr.to_enum(:scan,re).map {$&}
/(\d+)[m-t]/
Nicht/\d+[m-t]/
schreiben:re = /(\d+)[m-t]/; str.scan(re)
ist derselbe,str.scan(/(\d+)[mt]/)
aber ich erhalte #>[["" 54 "], [" 1 "], [" 3 "]]
und nicht"54m", "1t", "3r"]
Die Frage war: Wenn ich einen regulären Ausdruck mit einer Gruppe habe und alle Muster erfassen möchte, ohne den regulären zu ändern Ausdruck (Verlassen der Gruppe), wie kann ich das machen? In diesem Sinne war eine mögliche Lösung, wenn auch etwas kryptisch und schwer zu lesen ,:str.to_enum(:scan,re).map {$&}
Sie können verwenden
string.scan(your_regex).flatten
. Wenn Ihre Regex Gruppen enthält, wird sie in einem einzelnen einfachen Array zurückgegeben.Regex kann auch eine benannte Gruppe sein.
Sie können auch verwenden
gsub
, es ist nur eine weitere Möglichkeit, wenn Sie MatchData möchten.quelle
your_regex = /(\d+)[m-t]/
und Sie müssen sie nicht verwendenflatten
. Ihr letztes Beispiel verwendet,last_match
was in diesem Fall wahrscheinlich sicher ist, aber global ist und möglicherweise überschrieben werden könnte, wenn vor dem Aufruf ein regulärer Ausdruck gefunden wurdelast_match
. Stattdessen ist es wahrscheinlich sicherer zu verwendenstring.match(regex).captures # => ["group_photo", "jpg"]
oderstring.scan(/\d+/) # => ["54", "3", "1", "7", "3", "0"]
wie in anderen Antworten gezeigt, je nach Muster und Anforderungen.