Co to jest grupa nie przechwytywania w wyrażeniach regularnych?

W Jaki Sposób w wyrażeniach regularnych używane są grupy nie-przechwytywające, tj. (?:) i do czego służą?

Author: entpnerd, 2010-08-18

15 answers

Spróbuję to wyjaśnić na przykładzie.

Rozważ następujący tekst:

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

Teraz, jeśli zastosuję regex poniżej nad nim...

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

... Otrzymałbym następujący wynik:

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"

Ale nie obchodzi mnie protokół -- chcę tylko host i ścieżkę URL. Tak więc zmieniam regex na include nie przechwytywania grupy (?:).

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

Teraz mój wynik wygląda tak:

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"
Widzisz? Pierwsza grupa nie została schwytana. Parser używa go do dopasowania tekstu, ale ignoruje go później, w wyniku końcowym.

EDIT:

Zgodnie z życzeniem, pozwól, że spróbuję wyjaśnić grupy.

Cóż, grupy służą wielu celom. Mogą one pomóc w wyodrębnieniu dokładnych informacji z większego meczu (który można również nazwać), pozwalają na rewanż poprzedniej dopasowanej grupy i mogą być używane do zastępstw. Spróbujmy na przykładach.

Wyobraź sobie, że masz jakiś XML lub HTML (pamiętaj, że regex może nie być najlepszym narzędziem do zadania , ale jest to dobry przykład). Chcesz przeanalizować tagi, więc możesz zrobić coś takiego (dodałem spacje, aby ułatwić zrozumienie):

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

Pierwszy regex ma nazwaną grupę (TAG), podczas gdy drugi używa wspólnej grupy. Oba wyrażenia regularne robią to samo: używają wartości z pierwszej grupy (nazwy znacznika), aby dopasować znacznik zamykający. Różnica polega na tym, że pierwszy używa nazwy, aby dopasować wartość, a druga Używa indeksu grupy (który zaczyna się od 1).

Spróbujmy teraz zastąpienia. Rozważmy następujący tekst:

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

Teraz użyjmy tego głupiego regex nad nim:

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

Ten regex dopasowuje słowa z co najmniej 3 znakami i używa grup do oddzielenia pierwszych trzech liter. Wynik jest taki:

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"
...

Więc, jeśli zastosujemy ciąg podstawienia:

$1_$3$2_$4

... nad nim, staramy się użyć pierwszej grupy, dodać podkreślenie, użyj trzeciej grupy, następnie drugiej grupy, dodaj kolejny podkreślenie, a następnie czwartą grupę. Wynikowy ciąg będzie taki jak ten poniżej.

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.

Możesz również używać nazwanych grup dla podstawień, używając ${name}.

Aby bawić się regexami, polecam http://regex101.com/, który oferuje dużą ilość szczegółów na temat tego, jak działa regex; oferuje również kilka silników regex do wyboru.

 2507
Author: Ricardo Nolde,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-01 17:43:33

Grupy przechwytywania Można używać do porządkowania i analizowania wyrażenia. Grupa bez przechwytywania ma pierwszą korzyść, ale nie ma narzutu drugiego. Można na przykład powiedzieć, że grupa nie przechwytywająca jest opcjonalna.

Powiedzmy, że chcesz dopasować tekst liczbowy, ale niektóre liczby można zapisać jako 1., 2., 3., 4.,... Jeśli chcesz przechwycić część numeryczną, ale nie przyrostek (opcjonalny), możesz użyć grupy nie przechwytywającej.

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

Które będą pasowały do liczb w postaci 1, 2, 3... lub w formie 1., 2., 3.,... ale przechwyci tylko część numeryczną.

 196
Author: Bill the Lizard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-18 13:30:43

?: jest używany, gdy chcesz pogrupować wyrażenie, ale nie chcesz go zapisać jako dopasowaną / przechwyconą część łańcucha.

Przykładem może być coś, co pasuje do adresu IP:

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

Zauważ, że nie zależy mi na zapisaniu pierwszych 3 oktetów, ale grupowanie (?:...) pozwala mi skrócić wyrażenia regularne bez ponoszenia kosztów przechwytywania i przechowywania dopasowania.

 113
Author: RC.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-18 13:27:31

Sprawia, że grupa nie jest przechwytywana, co oznacza, że podłańcuch dopasowany do tej grupy nie zostanie uwzględniony na liście przechwytywanych. Przykład w Rubim, aby zilustrować różnicę:

"abc".match(/(.)(.)./).captures #=> ["a","b"]
"abc".match(/(?:.)(.)./).captures #=> ["b"]
 39
Author: sepp2k,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-18 13:23:33

MOTYWACJA HISTORYCZNA:

Istnienie grup niehablujących można wyjaśnić za pomocą nawiasu.

Rozważmy wyrażenia (a|b)c i a|bc, ze względu na priorytet konkatenacji nad |, wyrażenia te reprezentują dwa różne języki (odpowiednio{ac, bc} i {a, bc}).

Jednak nawiasy są również używane jako pasująca Grupa (jak wyjaśniono w innych odpowiedziach...).

Gdy chcesz mieć nawias, ale nie przechwytywać pod-wyrażenia używasz grup nie przechwytywanych. W przykładzie (?:a|b)c

 35
Author: user2369060,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-12-31 16:25:49

Pozwól, że spróbuję z przykładem:

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

Szukany Ciąg:

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

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

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

(?:animal) --> Grupa 1

(?:=)--> Grupa 2

(\w+)--> Grupa 1

(,)--> Grupa 2

\1 --> wynik przechwyconej grupy 1 tj. w linii 1 jest cat, w linii 2 jest cat, w linii 3 jest pies.

\2 --> wynik przechwyconej grupy 2 i. e przecinek (,)

Tak więc w tym kodzie podając \1 i \2 przypominamy lub powtarzamy wynik przechwyconej grupy 1 i 2 odpowiednio później w kodzie.

Zgodnie z kolejnością kodu (?:animal) powinna być grupa 1, a (?:=) powinna być grupa 2 i kontynuuje..

Ale podając ?: sprawiamy, że grupa meczowa nie jest przechwycona (która nie liczy się w dopasowanej grupie, więc numer grupy zaczyna się od pierwszej przechwyconej grupy i Nie Nie przechwycone), tak, że powtórzenie wyniku match-group (?:animal) nie może być wywołane później w kodzie.

Mam nadzieję, że to wyjaśnia użycie grupy bez przechwytywania.

Tutaj wpisz opis obrazka

 28
Author: shekhar gehlot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-12-31 16:23:14

Grupy, które przechwytywają możesz użyć później w regex, aby dopasować lub możesz użyć ich w części zamiennej regex. Tworzenie grupy nie-przechwytywania po prostu zwalnia tę grupę z użycia z jednego z tych powodów.

Grupy bez przechwytywania są świetne, jeśli próbujesz uchwycić wiele różnych rzeczy i są grupy, których nie chcesz przechwycić.

To właściwie powód, dla którego istnieją. Podczas nauki o grupy, dowiedz się o atomowych grupach , robią wiele! Istnieją również grupy lookaround, ale są one nieco bardziej złożone i nie są używane tak często.

Przykład użycia później w regex (backreference):

<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1> [ znajduje znacznik xml (bez obsługi ns)]

([A-Z][A-Z0-9]*) jest to grupa przechwytywania (w tym przypadku jest to tagname)

Później w regex jest \1, co oznacza, że będzie pasował tylko do tego samego tekstu, który był w pierwszej grupie (Grupa ([A-Z][A-Z0-9]*)) (w tym wielkość liter odpowiada znacznikowi końcowemu).

 15
Author: Bob Fincheimer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-18 13:33:03

Tl; dr nie-przechwytywanie grup, jak sama nazwa wskazuje są częściami wyrażenia regularnego, których nie chcesz zawierać w dopasowaniu i ?: jest sposobem na zdefiniowanie grupy jako nie-przechwytywanie.

Załóżmy, że masz adres e-mail [email protected]. Poniższy regex utworzy dwie grupy , część id i @example.com część. (\p{Alpha}*[a-z])(@example.com). Dla uproszczenia wyodrębniamy całą nazwę domeny łącznie ze znakiem @.

Powiedzmy, że potrzebujesz tylko dowodu tożsamości część adresu. To, co chcesz zrobić, to pobrać pierwszą grupę wyniku dopasowania, otoczoną przez () w wyrażeniu regularnym, a sposobem na to jest użycie składni nie przechwytywającej grupy, tj. ?:. Tak więc regex (\p{Alpha}*[a-z])(?:@example.com) zwróci tylko część id wiadomości e-mail.

 13
Author: Aaron S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-11 05:27:03

Nie mogę skomentować najlepszych odpowiedzi, aby powiedzieć to: chciałbym dodać wyraźny punkt, który jest sugerowany tylko w najlepszych odpowiedziach:

Grupa Nie-przechwytywania (?...) czy nie usuwa żadnych znaków z oryginalnego pełnego dopasowania, tylko reorganizuje regex wizualnie do programisty.

Aby uzyskać dostęp do określonej części wyrażenia regularnego bez zdefiniowanych obcych znaków, zawsze musisz użyć .group(<index>)

 10
Author: Scott Anderson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-02 01:04:00

Cóż, jestem programistą JavaScript i postaram się wyjaśnić jego znaczenie odnoszące się do JavaScript.

Rozważ scenariusz, w którym chcesz dopasować cat is animal kiedy chcesz dopasować kota i zwierzę i oba powinny mieć is pomiędzy nimi.

 // 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"]
 9
Author: Gaurav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-01 10:00:36

W złożonych wyrażeniach regularnych może pojawić się sytuacja, w której chcesz użyć dużej liczby grup, z których część służy do dopasowywania powtórzeń, a część do dostarczania odniesień zwrotnych. Domyślnie tekst pasujący do każdej grupy jest ładowany do tablicy backreference. Jeśli mamy wiele grup i musimy tylko móc odwołać się do niektórych z nich z tablicy backreference, możemy nadpisać to domyślne zachowanie, aby powiedzieć wyrażeniu regularnemu, że pewne grupy służą tylko do obsługi powtórzeń i nie muszą być przechwytywane i zapisywane w tablicy backreference.

 7
Author: Jack Peng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-08 17:33:15

Jedną z ciekawych rzeczy, na które natknąłem się, jest fakt, że możesz mieć grupę przechwytywania wewnątrz grupy nie przechwytywania. Zobacz poniżej wyrażenia regularne dla pasujących adresów URL:

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

Input URL string:

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

Pierwsza grupa w moim regex (?:([A-Za-z]+):) jest grupą nie przechwytywającą, która pasuje do schematu protokołu i dwukropka : znak tzn. http: ale kiedy uruchamiałem poniżej kodu, zauważyłem, że pierwszy indeks zwracanej tablicy zawiera łańcuch http Kiedy byłem myślenie, że http i dwukropek : nie zostaną zgłoszone, ponieważ znajdują się w grupie nie przechwytywającej.

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

Tutaj wpisz opis obrazka

Pomyślałem, że jeśli pierwsza grupa (?:([A-Za-z]+):) jest grupą nie przechwytywającą, to dlaczego zwraca http string w wyjściowej tablicy.

Więc jeśli zauważysz, że wewnątrz grupy nie przechwytywającej znajduje się zagnieżdżona grupa ([A-Za-z]+). Ta zagnieżdżona grupa ([A-Za-z]+) jest grupą przechwytywającą (nie mającą ?: na początku) samą w sobie wewnątrz grupy nie przechwytywającej (?:([A-Za-z]+):). Dlatego tekst http jest nadal przechwytywany, ale dwukropek :, który znajduje się wewnątrz grupy nie przechwytywającej, ale poza Grupą przechwytywającą, nie jest raportowany w macierzy wyjściowej.

 7
Author: RBT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-15 03:34:42

Myślę, że dam ci odpowiedź. Nie używaj zmiennych przechwytywania bez sprawdzenia, czy dopasowanie się powiodło.

Zmienne przechwytywania, $1 itd. nie są ważne, dopóki dopasowanie się nie powiodło, i też nie są wyczyszczone.

#!/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";
}

W powyższym przykładzie, aby uniknąć uchwycenia bronto w $1, (?:) jest używany.

Jeśli wzór jest dopasowany, to {[2] } jest przechwytywany jako następny zgrupowany wzór.

Tak, Wyjście będzie jak poniżej:

Fred wants a burger

Jest Przydatne, jeśli nie chcesz, aby dopasowania były zapisywane.

 3
Author: Harini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-12-31 16:24:49

Otwórz Google Chrome devTools, a następnie Console tab: i wpisz to:

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

Uruchom go, a zobaczysz:

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

Silnik RegExp JavaScript przechwytuje trzy grupy, pozycje z indeksami 1,2,3. Teraz użyj znacznika bez przechwytywania, aby zobaczyć wynik.

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

Wynik jest następujący:

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

Jest to oczywiste, co nie jest grupą przechwytywania.

 2
Author: AmerllicA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-07 03:50:43

Jest to niezwykle proste, możemy zrozumieć za pomocą prostego przykładu daty, Załóżmy, że jeśli data jest wymieniona jako 1st January 2019 lub 2nd May 2019 lub jakakolwiek inna data i chcemy po prostu przekonwertować ją do formatu dd/mm/RRRR, nie potrzebujemy nazwy miesiąca, która jest Styczeń lub luty, więc aby uchwycić część numeryczną, ale nie (opcjonalny) sufiks, możesz użyć grupy nie przechwytywającej.

Więc wyrażenie regularne będzie,

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

Its as simple as to.

 2
Author: Naved Ahmad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-07 08:08:48