Wie kann man mehrere wiederholte Gruppen erfassen?


79

Ich muss mehrere Gruppen desselben Musters erfassen. Angenommen, ich habe eine folgende Zeichenfolge:

HELLO,THERE,WORLD

Und ich habe ein folgendes Muster geschrieben

^(?:([A-Z]+),?)+$

Ich möchte, dass jedes einzelne Wort erfasst wird, sodass Gruppe 1 lautet: "HALLO", Gruppe 2 ist "THERE" und Gruppe 3 ist "WORLD". Was meine Regex tatsächlich erfasst, ist nur das letzte, nämlich " WELT".

Ich teste meinen regulären Ausdruck hier und ich will , es benutzen mit Swift (vielleicht gibt es eine Möglichkeit , in Swift irgendwie Zwischenergebnisse zu bekommen, so dass ich sie nicht verwenden kann?)

UPDATE: Ich möchte nicht verwenden split. Ich muss jetzt nur noch lernen, wie alle Gruppen erfasst werden, die dem Muster entsprechen, nicht nur die letzte.


5
warum nicht weiter aufteilen ,?
Rock321987

Warum nicht verwenden [A-Z]+oder [^,]+die Ergebnisse erfassen
Rock321987

rock321987, ich habe die Eingabezeichenfolge aktualisiert. Ich muss genau die Zeichenfolge extrahieren, die dem obigen Muster folgt. Und ich muss dafür sorgen, dass alle Gruppen dem Muster entsprechen, nicht nur die letzte. Ich möchte wissen, wie es mit Regex geht.
Phbelov

1
rock321987, was ist unklar? Ich brauche jedes Wort der Zeichenfolge, um eine übereinstimmende Gruppe zu sein, aber mein Muster erfasst nur das letzte ("WORLD").
Phbelov

1
Verwenden Sie diese Antwort, um alle Übereinstimmungen zu finden
rock321987

Antworten:


59

Mit einer Gruppe im Muster können Sie nur ein genaues Ergebnis in dieser Gruppe erhalten. Wenn Ihre Erfassungsgruppe durch das Muster wiederholt wird (Sie haben den +Quantifizierer für die umgebende nicht erfassende Gruppe verwendet), wird nur der letzte übereinstimmende Wert gespeichert.

Sie müssen die Regex-Implementierungsfunktionen Ihrer Sprache verwenden, um alle Übereinstimmungen eines Musters zu finden. Dann müssten Sie die Anker und den Quantifizierer der nicht erfassenden Gruppe entfernen (und Sie könnten auch die nicht erfassende Gruppe selbst weglassen).

Erweitern Sie alternativ Ihren regulären Ausdruck und lassen Sie das Muster eine Erfassungsgruppe pro Gruppe enthalten, die Sie im Ergebnis erhalten möchten:

^([A-Z]+),([A-Z]+),([A-Z]+)$

13
Wie würde dies angepasst, um eine unterschiedliche Anzahl von Zeichenfolgen zu berücksichtigen? zB HALLO, WELT und HALLO, DA, MEINE, WELT. Ich suche nur einen Ausdruck, um beide Beispiele zu handhaben und mit Flexibilität für noch längere String-Arrays
Chris

9
@ Chris Es kann nicht verallgemeinert werden. Wie in der Antwort angegeben, kann eine Erfassungsgruppe nur eines erfassen, und es gibt keine Möglichkeit, eine dynamische Anzahl von Erfassungsgruppen zu erstellen.
Barmar

6

Ich denke du brauchst so etwas ....

b="HELLO,THERE,WORLD"
re.findall('[\w]+',b)

Welche in Python3 wird zurückkehren

['HELLO', 'THERE', 'WORLD']

3

Nur um ein zusätzliches Beispiel für Absatz 2 in der Antwort zu liefern. Ich bin mir nicht sicher, wie wichtig es für Sie ist, drei Gruppen in einem Spiel zu erhalten, anstatt drei Spiele mit einer Gruppe. ZB in groovig:

def subject = "HELLO,THERE,WORLD"
def pat = "([A-Z]+)"
def m = (subject =~ pat)
m.eachWithIndex{ g,i ->
  println "Match #$i: ${g[1]}"
}

Match #0: HELLO
Match #1: THERE
Match #2: WORLD

2

Nachdem ich die Antwort von Byte Commander gelesen habe , möchte ich eine winzige mögliche Verbesserung vorstellen:

Sie können einen regulären Ausdruck generieren, der mit beiden nWörtern übereinstimmt , solange Ihr Wort nvorbestimmt ist. Wenn ich zum Beispiel zwischen 1 und 3 Wörtern abgleichen möchte, wird der reguläre Ausdruck:

^([A-Z]+)(?:,([A-Z]+))?(?:,([A-Z]+))?$

wird die nächsten Sätze mit einer, zwei oder drei Erfassungsgruppen abgleichen.

HELLO,LITTLE,WORLD
HELLO,WORLD
HELLO

Sie können eine ausführliche Erklärung zu diesem regulären Ausdruck auf Regex101 sehen .

Wie gesagt, es ist ziemlich einfach, diesen regulären Ausdruck für alle Gruppen zu generieren, die Sie mit Ihrer Lieblingssprache verwenden möchten. Da ich kein besonders schneller Typ bin, hier ein Rubinbeispiel:

def make_regexp(group_regexp, count: 3, delimiter: ",")
  regexp_str = "^(#{group_regexp})"
  (count - 1).times.each do
    regexp_str += "(?:#{delimiter}(#{group_regexp}))?"
  end
  regexp_str += "$"
  return regexp_str
end

puts make_regexp("[A-Z]+")

Abgesehen davon würde ich vorschlagen, in diesem Fall keinen regulären Ausdruck zu verwenden. Es gibt viele andere großartige Tools, von einfachen splitbis zu einigen Tokenisierungsmustern, je nach Ihren Anforderungen. IMHO, ein regulärer Ausdruck gehört nicht dazu. Zum Beispiel würde ich in Ruby so etwas wie str.split(",")oder verwendenstr.scan(/[A-Z]+/)


1

Sie haben tatsächlich eine Erfassungsgruppe, die mehrmals übereinstimmt. Nicht mehrere Erfassungsgruppen.

Javascript (js) -Lösung:

let string = "HI,THERE,TOM";
let myRegexp = /([A-Z]+),?/g;       //modify as you like
let match = myRegexp.exec(string);  //js function, output described below
while(match!=null){                 //loops through matches
    console.log(match[1]);          //do whatever you want with each match
    match = myRegexp.exec(bob);     //find next match
}

Ausgabe:

HI
THERE
TOM

Syntax:

// matched text: match[0]
// match start: match.index
// capturing group n: match[n]

Wie Sie sehen können, funktioniert dies für eine beliebige Anzahl von Übereinstimmungen.


0

Ich weiß, dass meine Antwort zu spät kam, aber es passiert mir heute und ich habe sie mit folgendem Ansatz gelöst:

^(([A-Z]+),)+([A-Z]+)$

Die erste Gruppe (([A-Z]+),)+stimmt also mit allen wiederholten Mustern überein, mit Ausnahme des letzten ([A-Z]+), das mit dem letzten übereinstimmt. und dies wird dynamisch sein, egal wie viele wiederholte Gruppen in der Zeichenfolge.


1
Dies ist keine Lösung für das Problem. Bei der Frage geht es nicht darum, die Zeichenfolge abzugleichen, sondern alle Gruppen zu erfassen. Diese Regex erfasst immer noch nur die letzte Übereinstimmung für die erste sich wiederholende Gruppe (mit Komma) sowie die Übereinstimmung in der letzten Gruppe (ohne Komma).
Zwerg
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.