Wie erfasse ich eine beliebige Anzahl von Gruppen in JavaScript Regexp?

81

Ich würde diese Zeile von JavaScript erwarten:

"foo bar baz".match(/^(\s*\w+)+$/)

etwas zurückgeben wie:

["foo bar baz", "foo", " bar", " baz"]

Stattdessen wird nur das zuletzt erfasste Spiel zurückgegeben:

["foo bar baz", " baz"]

Gibt es eine Möglichkeit, alle erfassten Übereinstimmungen zu erhalten?

disc0dancer
quelle

Antworten:

90

Wenn Sie eine Erfassungsgruppe wiederholen, wird in den meisten Varianten nur die letzte Erfassung beibehalten. Alle vorherigen Erfassungen werden überschrieben. In einigen Varianten, z. B. .NET, können Sie alle Zwischenerfassungen erhalten, dies ist jedoch bei Javascript nicht der Fall.

Das heißt, wenn Sie in Javascript ein Muster mit N Erfassungsgruppen haben, können Sie nur genau N Zeichenfolgen pro Übereinstimmung erfassen , selbst wenn einige dieser Gruppen wiederholt wurden.

Im Allgemeinen also, je nachdem, was Sie tun müssen:

  • Wenn dies eine Option ist, teilen Sie stattdessen die Trennzeichen auf
  • Anstatt zu /(pattern)+/passen /pattern/g, vielleicht zu passen , vielleicht in einer execSchleife
    • Beachten Sie, dass diese beiden nicht genau gleichwertig sind, dies kann jedoch eine Option sein
  • Führen Sie einen mehrstufigen Abgleich durch:
    • Erfassen Sie die wiederholte Gruppe in einem Spiel
    • Führen Sie dann einen weiteren regulären Ausdruck aus, um das Match auseinanderzubrechen

Verweise


Beispiel

Hier ist ein Beispiel für das Abgleichen <some;words;here>in einem Text mithilfe einer execSchleife und das anschließende Aufteilen ;, um einzelne Wörter zu erhalten ( siehe auch auf ideone.com ):

var text = "a;b;<c;d;e;f>;g;h;i;<no no no>;j;k;<xx;yy;zz>";

var r = /<(\w+(;\w+)*)>/g;

var match;
while ((match = r.exec(text)) != null) {
  print(match[1].split(";"));
}
// c,d,e,f
// xx,yy,zz

Das verwendete Muster ist:

      _2__
     /    \
<(\w+(;\w+)*)>
 \__________/
      1

Dazu passt <word>, <word;another>, <word;another;please>etc. Gruppe 2 wird wiederholt eine beliebige Anzahl von Wörtern zu erfassen, aber es kann nur die letzte Erfassung halten. Die gesamte Liste der Wörter wird von Gruppe 1 erfasst. Diese Zeichenfolge befindet sich dann splitim Semikolon-Trennzeichen.

Verwandte Fragen

Polygenschmierstoffe
quelle
7

Wie wäre es damit? "foo bar baz".match(/(\w+)+/g)

meder omuraliev
quelle
Ihr Code funktioniert, aber das Hinzufügen eines globalen Flags zu meinem Beispiel löst das Problem nicht: "foo bar baz" .match (/ ^ (\ s * \ w +) + $ / g) gibt ["foo bar baz"] zurück.
Disc0Dancer
Es funktioniert, wenn Sie es unten in den regulären Ausdruck von @ Jet ändern. "foo bar baz".match(/\w+/g) //=> ["foo", "bar", "baz"]. Es ignoriert die übereinstimmende Zeichenfolge an der Vorderseite, ist aber immer noch eine vernünftige Alternative.
Jed Schneider
6

Sofern Sie keine komplizierteren Anforderungen für die Aufteilung Ihrer Zeichenfolgen haben, können Sie diese aufteilen und dann die ursprüngliche Zeichenfolge mit ihnen zurückgeben:

var data = "foo bar baz";
var pieces = data.split(' ');
pieces.unshift(data);
gddc
quelle
1
Dies war nur der Ratschlag, den ich brauchte, um mich zu wecken, dass ich zumindest für meine aktuelle Anwendung nichts Anspruchsvolleres als split () brauchte.
Hephaistos
4

versuche es mit 'g':

"foo bar baz".match(/\w+/g)
Jet
quelle