it-swarm.com.de

Was ist eine nicht einnehmende Gruppe? Was macht (? :)?

Wie wird ?: verwendet und wofür ist es gut?

1462

Lassen Sie mich das an einem Beispiel erklären.

Betrachten Sie den folgenden Text:

http://stackoverflow.com/
https://stackoverflow.com/questions/tagged/regex

Nun, wenn ich die Regex unten anwenden ...

(https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?

... würde ich folgendes Ergebnis erhalten:

Match "http://stackoverflow.com/"
     Group 1: "http"
     Group 2: "stackoverflow.com"
     Group 3: "/"

Match "https://stackoverflow.com/questions/tagged/regex"
     Group 1: "https"
     Group 2: "stackoverflow.com"
     Group 3: "/questions/tagged/regex"

Das Protokoll interessiert mich jedoch nicht - ich möchte nur den Host und den Pfad der URL. Also ändere ich die Regex so, dass sie die nicht erfassende Gruppe (?:) enthält.

(?:https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?

Nun sieht mein Ergebnis so aus:

Match "http://stackoverflow.com/"
     Group 1: "stackoverflow.com"
     Group 2: "/"

Match "https://stackoverflow.com/questions/tagged/regex"
     Group 1: "stackoverflow.com"
     Group 2: "/questions/tagged/regex"

Sehen? Die erste Gruppe wurde nicht erfasst. Der Parser verwendet ihn, um den Text abzugleichen, ignoriert ihn jedoch später im Endergebnis.


BEARBEITEN:

Lassen Sie mich, wie gewünscht, auch Gruppen erklären.

Nun, Gruppen dienen vielen Zwecken. Sie können Ihnen dabei helfen, exakte Informationen aus einem größeren Match (das auch benannt werden kann) zu extrahieren, eine vorherige Matching-Gruppe erneut abzustimmen und für Ersetzungen verwendet werden. Lassen Sie uns einige Beispiele ausprobieren, oder?

Stellen Sie sich vor, Sie haben eine Art XML oder HTML (beachten Sie, dass regex nicht das beste Werkzeug für den Job ist , aber es ist Nizza als Beispiel). Sie möchten die Tags analysieren, damit Sie so etwas tun können (ich habe Leerzeichen hinzugefügt, um das Verständnis zu erleichtern):

   \<(?<TAG>.+?)\> [^<]*? \</\k<TAG>\>
or
   \<(.+?)\> [^<]*? \</\1\>

Der erste reguläre Ausdruck hat eine benannte Gruppe (TAG), während der zweite eine gemeinsame Gruppe verwendet. Beide Ausdrücke machen dasselbe: Sie verwenden den Wert der ersten Gruppe (den Namen des Tags), um mit dem schließenden Tag übereinzustimmen. Der Unterschied besteht darin, dass der erste den Namen verwendet, um den Wert zu finden, und der zweite den Gruppenindex (der bei 1 beginnt).

Lassen Sie uns jetzt einige Substitutionen ausprobieren. Betrachten Sie den folgenden Text:

Lorem ipsum dolor sit amet consectetuer feugiat fames malesuada pretium egestas.

Jetzt lass uns die dumme Regex darüber verwenden:

\b(\S)(\S)(\S)(\S*)\b

Dieser Ausdruck entspricht Wörtern mit mindestens 3 Zeichen und verwendet Gruppen, um die ersten drei Buchstaben voneinander zu trennen. Das Ergebnis ist folgendes:

Match "Lorem"
     Group 1: "L"
     Group 2: "o"
     Group 3: "r"
     Group 4: "em"
Match "ipsum"
     Group 1: "i"
     Group 2: "p"
     Group 3: "s"
     Group 4: "um"
...

Match "consectetuer"
     Group 1: "c"
     Group 2: "o"
     Group 3: "n"
     Group 4: "sectetuer"
...

Also, wenn wir die Substitutionszeichenfolge anwenden ...

$1_$3$2_$4

... darüber hinaus versuchen wir, die erste Gruppe zu verwenden, einen Unterstrich hinzuzufügen, die dritte Gruppe zu verwenden, dann die zweite Gruppe, einen weiteren Unterstrich hinzuzufügen und dann die vierte Gruppe. Die resultierende Zeichenfolge würde wie die folgende sein.

L_ro_em i_sp_um d_lo_or s_ti_ a_em_t c_no_sectetuer f_ue_giat f_ma_es m_la_esuada p_er_tium e_eg_stas.

Sie können auch benannte Gruppen für Substitutionen verwenden, indem Sie ${name} verwenden.

Um mit Regexes herumzuspielen, empfehle ich http://regex101.com/ , die eine Menge Details zur Funktionsweise des Regex enthält. Es bietet auch ein paar Regex-Engines zur Auswahl.

1994
Ricardo Nolde

Sie können Erfassungsgruppen verwenden, um einen Ausdruck zu organisieren und zu analysieren. Eine Gruppe ohne Capturing hat den ersten Vorteil, aber nicht den Aufwand der zweiten. Sie können immer noch sagen, dass eine Gruppe, die keine Captures erfasst, optional ist.

Angenommen, Sie möchten numerischen Text abgleichen, aber einige Zahlen könnten als 1., 2., 3., 4. geschrieben werden. Wenn Sie den numerischen Teil, jedoch nicht das (optionale) Suffix erfassen möchten, können Sie eine Gruppe ohne Erfassung verwenden .

([0-9]+)(?:st|nd|rd|th)?

Dies entspricht den Zahlen in der Form 1, 2, 3 ... oder in der Form 1, 2, 3, ..., aber es wird nur der numerische Teil erfasst.

143
Bill the Lizard

?: wird verwendet, wenn Sie einen Ausdruck gruppieren möchten, ihn jedoch nicht als übereinstimmenden/erfassten Teil der Zeichenfolge speichern möchten.

Ein Beispiel wäre etwas, das mit einer IP-Adresse übereinstimmt:

/(?:\d{1,3}\.){3}\d{1,3}/

Beachten Sie, dass es mir nicht wichtig ist, die ersten 3 Oktette zu speichern, aber die (?:...)-Gruppierung ermöglicht es mir, den Regex zu verkürzen, ohne den Aufwand für das Erfassen und Speichern einer Übereinstimmung zu verursachen. 

93
RC.

Dadurch wird die Gruppe nicht erfasst. Dies bedeutet, dass der von dieser Gruppe übereinstimmende Teilstring nicht in die Liste der Aufnahmen aufgenommen wird. Ein Beispiel in Ruby, um den Unterschied zu veranschaulichen:

"abc".match(/(.)(.)./).captures #=> ["a","b"]
"abc".match(/(?:.)(.)./).captures #=> ["b"]
30
sepp2k

HISTORISCHE MOTIVATION: Das Vorhandensein nicht erfassender Gruppen kann durch die Verwendung von Klammern erklärt werden. Betrachten Sie die Ausdrücke (a | b) c und a | bc aufgrund der Priorität der Verkettung vor |; diese Ausdrücke repräsentieren zwei verschiedene Sprachen ({ac, bc} und {a, bc}). Die Klammern werden jedoch auch als übereinstimmende Gruppe verwendet (wie in den anderen Antworten erläutert).

Wenn Sie Klammern haben möchten, den Unterausdruck jedoch nicht erfassen möchten, verwenden Sie NON-CAPTURING GROUPS. Im Beispiel (?: A | b) c

16
user2369060

Gruppen, die capture Sie später in der Regex verwenden können, um mit ODER übereinzustimmen, können Sie sie im ersetzenden Teil der Regex verwenden. Wenn Sie eine non-capturing -Gruppe erstellen, wird die Gruppe aus einem dieser Gründe einfach von der Verwendung ausgeschlossen. 

Gruppen ohne Capture sind großartig, wenn Sie viele verschiedene Dinge erfassen möchten und es einige Gruppen gibt, die Sie nicht erfassen möchten. 

Das ist so ziemlich der Grund, warum sie existieren. Während Sie etwas über Gruppen lernen, erfahren Sie mehr über Atomic Groups , sie leisten viel! Es gibt auch Lookaround-Gruppen, aber diese sind etwas komplexer und werden nicht so häufig verwendet.

Beispiel für die Verwendung später in der Regex (Rückverweis):

<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1> [Findet ein XML-Tag (ohne ns-Unterstützung)]

([A-Z][A-Z0-9]*) ist eine Erfassungsgruppe (in diesem Fall ist dies der Tagname)

Später in der Regex steht \1, was bedeutet, dass nur derselbe Text wie in der ersten Gruppe (der ([A-Z][A-Z0-9]*)-Gruppe) übereinstimmt (in diesem Fall stimmt der End-Tag überein).

13
Bob Fincheimer

Lass es mich mit einem Beispiel versuchen: -

Regex-Code: - (?:animal)(?:=)(\w+)(,)\1\2

Suchbegriff :-

Zeile 1 - animal=cat,dog,cat,tiger,dog

Zeile 2 - animal=cat,cat,dog,dog,tiger

Zeile 3 - animal=dog,dog,cat,cat,tiger

(?:animal) -> Nicht erfasste Gruppe 1

(?:=)--> Gruppe nicht erfasst 2

(\w+)--> Gruppe erfasst 1

(,)--> Gruppe erfasst 2

\1 -> Ergebnis der erfassten Gruppe 1, d. h. In Zeile 1 ist Katze, In Zeile 2 ist Katze, In Zeile 3 ist Hund.

\2 -> Ergebnis der erfassten Gruppe 2, dh Komma (,)

In diesem Code rufen wir also mit\1 und\2 das Ergebnis der erfassten Gruppe 1 bzw. 2 später im Code auf.

Gemäß der Reihenfolge des Codes (?: Tier) sollte Gruppe 1 sein und (?: =) Sollte Gruppe 2 sein und fortgesetzt werden.

aber indem wir das? geben: machen wir die Match-Gruppe nicht erfasst (was in der übereinstimmenden Gruppe nicht abgezählt wird, die Gruppierungsnummer beginnt also bei der ersten Gruppe und nicht bei der Nicht-Gruppe), so dass das Ergebnis der Übereinstimmung wiederholt wird -group (?: animal) kann später nicht mehr im Code aufgerufen werden.

Ich hoffe, dies erklärt die Verwendung einer Gruppe ohne Erfassung.

Bildbeschreibung hier eingeben

10
shekhar gehlot

Nun, ich bin ein JavaScript-Entwickler und werde versuchen, seine Bedeutung in Bezug auf JavaScript zu erklären.

Stellen Sie sich ein Szenario vor, in dem Sie mit cat is animal Übereinstimmen möchten, wenn Sie mit Katze und Tier übereinstimmen möchten und beide eine is zwischen sich haben.

 // this will ignore "is" as that's is what we want
"cat is animal".match(/(cat)(?: is )(animal)/) ;
result ["cat is animal", "cat", "animal"]

 // using lookahead pattern it will match only "cat" we can
 // use lookahead but the problem is we can not give anything
 // at the back of lookahead pattern
"cat is animal".match(/cat(?= is animal)/) ;
result ["cat"]

 //so I gave another grouping parenthesis for animal
 // in lookahead pattern to match animal as well
"cat is animal".match(/(cat)(?= is (animal))/) ;
result ["cat", "cat", "animal"]

 // we got extra cat in above example so removing another grouping
"cat is animal".match(/cat(?= is (animal))/) ;
result ["cat", "animal"]
6
Gaurav

In komplexen regulären Ausdrücken kann es vorkommen, dass Sie eine Situation schaffen, in der Sie eine große Anzahl von Gruppen verwenden möchten, von denen einige für den Wiederholungsabgleich vorhanden sind und einige für Rückverweise. Standardmäßig wird der Text, der zu jeder Gruppe passt, in das Rückverweisarray geladen. Wenn wir viele Gruppen haben und nur einige von ihnen aus dem Backreference-Array referenzieren müssen, können Sie dieses Standardverhalten überschreiben, um dem regulären Ausdruck mitzuteilen, dass bestimmte Gruppen nur für die Wiederholungsbehandlung vorhanden sind und nicht erfasst und gespeichert werden müssen im Rückverweisfeld.

5
Jack Peng

Eine interessante Sache, auf die ich gestoßen bin, ist die Tatsache, dass Sie eine Capturing-Gruppe in einer Nicht-Capturing-Gruppe haben können. Unter regex finden Sie passende Web-URLs:

var parse_url_regex = /^(?:([A-Za-z]+):)(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;

Eingabe-URL-String:

var url = "http://www.ora.com:80/goodparts?q#fragment";

Die erste Gruppe in meinem Regex (?:([A-Za-z]+):) ist eine nicht erfassende Gruppe, die mit dem Protokollschema und dem Doppelpunkt :-Zeichen übereinstimmt, dh http:. Als ich jedoch unter Code lief, sah ich, dass der 1. Index des zurückgegebenen Arrays die Zeichenfolge http enthielt, als ich es war Ich denke, dass http und der Doppelpunkt : nicht gemeldet werden, da sie sich in einer Gruppe ohne Erfassung befinden.

console.debug(parse_url_regex.exec(url));

 enter image description here

Ich dachte, wenn die erste Gruppe (?:([A-Za-z]+):) eine nicht erfassende Gruppe ist, gibt sie aus, warum sie http string im Ausgabearray zurückgibt.

Wenn Sie also feststellen, dass es in der nicht erfassenden Gruppe eine verschachtelte Gruppe ([A-Za-z]+) gibt. Diese verschachtelte Gruppe ([A-Za-z]+) ist eine Erfassungsgruppe (die nicht ?: am Anfang hat) in einer nicht erfassenden Gruppe (?:([A-Za-z]+):). Aus diesem Grund wird der Text http immer noch erfasst, aber das Doppelpunktzeichen :, das sich innerhalb der nicht erfassenden Gruppe, jedoch außerhalb der erfassenden Gruppe befindet, wird nicht im Ausgabearray gemeldet.

4
RBT

tl; dr non-capturing-Gruppen, wie der Name schon sagt, sind die Teile des Regex, die nicht in das Match aufgenommen werden sollen, und ?: ist eine Möglichkeit, eine Gruppe als nicht-zu definieren. Erfassen.

Angenommen, Sie haben eine E-Mail-Adresse [email protected]. Der folgende Regex erstellt zwei groups , den ID-Teil und den @ example.com-Teil. (\p{Alpha}*[a-z])(@example.com). Der Einfachheit halber extrahieren wir den gesamten Domainnamen einschließlich des @ -Zeichens.

Nehmen wir an, Sie brauchen nur den ID-Teil der Adresse. Sie möchten die erste Gruppe des Übereinstimmungsergebnisses, umgeben von (), in der regulären Ausdrücke verwenden. Die Art und Weise, wie Sie dies tun, ist die Verwendung der Gruppensyntax ohne Erfassung, d. H. ?:. Der Regex (\p{Alpha}*[a-z])(?:@example.com) gibt also nur den ID-Teil der E-Mail zurück.

4
6pack kid

Ich kann die ersten Antworten nicht kommentieren, um dies zu sagen: Ich möchte einen expliziten Punkt hinzufügen, der nur in den oberen Antworten enthalten ist:

Die nicht erfassende Gruppe (?...) Führt nicht entfernen alle Zeichen aus der ursprünglichen vollständigen Übereinstimmung aus, nur sie reorganisiert die Regex visuell für den Programmierer. 

Um auf einen bestimmten Teil des regulären Ausdrucks ohne definierte überflüssige Zeichen zuzugreifen, müssen Sie immer .group(<index>) verwenden.

4
Scott Anderson

Ich denke, ich würde Ihnen die Antwort geben.... Verwenden Sie keine Capture-Variablen, ohne zu prüfen, ob die Übereinstimmung erfolgreich war.

Die Erfassungsvariablen $ 1 usw. sind nur gültig, wenn die Übereinstimmung erfolgreich war, und sie werden auch nicht gelöscht.

#!/usr/bin/Perl  
use warnings;
use strict;   
$_ = "bronto saurus burger";
if (/(?:bronto)? saurus (steak|burger)/)
{
    print "Fred wants a  $1";
}
else
{
    print "Fred dont wants a $1 $2";
}

Im obigen Beispiel wird (? :) verwendet, um das Aufzeichnen von Bronto in $ 1 zu vermeiden. Wenn das Muster übereinstimmt, wird $ 1 als das nächste gruppierte Muster .. erfasst. Die Ausgabe ist also wie folgt:

Fred wants a burger

Dies ist nützlich, wenn die Übereinstimmungen nicht gespeichert werden sollen.

1
Harini

Öffnen Sie Ihre Google Chrome devTools und dann die Registerkarte "Konsole": und geben Sie Folgendes ein:

"Peace".match(/(\w)(\w)(\w)/)

Führen Sie es aus und Sie werden sehen:

["Pea", "P", "e", "a", index: 0, input: "Peace", groups: undefined]

Die JavaScript RegExp-Engine erfasst drei Gruppen, die Elemente mit den Indizes 1, 2, 3. Verwenden Sie nun eine Nicht-Aufnahmemarke, um das Ergebnis zu sehen.

"Peace".match(/(?:\w)(\w)(\w)/)

Das Ergebnis ist:

["Pea", "e", "a", index: 0, input: "Peace", groups: undefined]

Dies ist offensichtlich, was Gruppe ist, die nicht erfasst.

0
AmerllicA

Es ist extrem einfach. Wir können mit einem einfachen Datumsbeispiel verstehen, dass das Datum als 1. Januar 2019 oder 2. Mai 2019 oder ein anderes Datum genannt wird und wir es einfach in das Format TT/MM/JJJJ konvertieren möchten Sie brauchen nicht den Monatsnamen (Januar oder Februar), um den numerischen Teil zu erfassen, nicht jedoch das (optionale) Suffix. Sie können eine Gruppe ohne Erfassung verwenden.

so wäre der reguläre Ausdruck,

([0-9]+)(?:January|February)?

So einfach ist das.

0
Naved Ahmad