Podobne do naszych wątków dotyczących golfowych wskazówek: jakie są ogólne sztuczki skracania wyrażeń regularnych?
Widzę trzy zastosowania wyrażenia regularnego, jeśli chodzi o golfa: klasyczny wyrażenie regularne („tutaj jest lista, która powinna pasować, a oto lista, która powinna zawieść”), użycie wyrażenia regularnego do rozwiązywania problemów obliczeniowych i wyrażeń regularnych używanych jako części większy kod do gry w golfa. Zapraszam do publikowania wskazówek dotyczących jednego lub wszystkich z nich. Jeśli Twoja wskazówka jest ograniczona do jednego lub więcej smaków, podaj te smaki u góry.
Jak zwykle, trzymaj się jednej wskazówki (lub rodziny bardzo blisko powiązanych wskazówek) na odpowiedź, aby najbardziej przydatne wskazówki mogły awansować na szczyt poprzez głosowanie.
źródło
Odpowiedzi:
Kiedy nie uciec
Te zasady dotyczą większości smaków, jeśli nie wszystkich:
]
nie potrzebuje ucieczki, gdy nie ma sobie równych.{
i}
nie trzeba uciekać, gdy nie są częścią powtórzenia, np.{a}
mecze{a}
dosłownie. Nawet jeśli chcesz coś dopasować{2}
, musisz uciec tylko jednemu z nich, np{2\}
.W klasach postaci:
]
nie musi uciekać, gdy jest to pierwsza postać w zestawie znaków, np.[]abc]
pasuje do jednego z znaków]abc
, lub gdy jest to druga postać po^
, np.[^]]
pasuje do wszystkiego oprócz]
. (Godny uwagi wyjątek: smak ECMAScript!)[
wcale nie potrzebuje ucieczki. W połączeniu z powyższą wskazówką oznacza to, że możesz dopasować oba nawiasy do okropnie intuicyjnej klasy postaci[][]
.^
nie potrzebuje ucieczki, kiedy to nie pierwszy znak w zestawie znaków, np[ab^c]
.-
nie potrzebuje ucieczki, kiedy to zarówno pierwszy (drugi po^
) lub ostatni znak w zestawie znaków, na przykład[-abc]
,[^-abc]
albo[abc-]
.Żadne inne znaki nie muszą uciekać wewnątrz klasy znaków, nawet jeśli są meta znakami poza klasami znaków (z wyjątkiem
\
samego ukośnika odwrotnego ).Ponadto, w niektórych smakach
^
i$
są dopasowywane dosłownie, gdy nie znajdują się odpowiednio na początku lub na końcu wyrażenia regularnego.(Podziękowania dla @ MartinBüttner za wypełnienie kilku szczegółów)
źródło
[.]
). Ucieczka to normalnie zaoszczędziłoby w tym przypadku 1 bajt\.
[
należy je zmienić w Javie. Nie jestem jednak pewien co do ICU (używane w Androidzie i iOS) lub .NET.Proste wyrażenie regularne pasujące do wszystkich drukowalnych znaków w tabeli ASCII .
źródło
Poznaj swoje smaki regularne
Zaskakująca jest liczba osób, które uważają, że wyrażenia regularne są zasadniczo niezależne od języka. Istnieją jednak dość znaczne różnice między smakami, a szczególnie w przypadku golfa kodowego dobrze jest znać kilka z nich i ich ciekawe funkcje, dzięki czemu możesz wybrać najlepsze dla każdego zadania. Oto przegląd kilku ważnych smaków i ich odróżnienie od innych. (Ta lista nie może być naprawdę kompletna, ale daj mi znać, jeśli coś przeoczyłem.)
Perl i PCRE
Wrzucam je do jednego garnka, ponieważ nie znam się zbytnio na smaku Perla i są one w większości równoważne (w końcu PCRE jest dla wyrażeń regularnych kompatybilnych z Perlem). Główną zaletą smaku Perla jest to, że można wywoływać kod Perla z wyrażenia regularnego i podstawiania.
(?(group)yes|no)
.\l
,\u
,\L
i\U
.\G
aby zakotwiczyć mecz do końca poprzedniego meczu.\K
zresetować początek meczu\Q...\E
aby uniknąć dłuższych serii znaków. Przydatne, gdy próbujesz dopasować ciąg znaków, który zawiera wiele metaznaków..NETTO
Jest to prawdopodobnie najsilniejszy smak, z bardzo niewielkimi niedociągnięciami.
[\w-[aeiou]]
\d
znają Unicode.Jednym z istotnych niedociągnięć pod względem golfowym jest to, że nie obsługuje kwantyfikatorów dzierżawczych, jak niektóre inne smaki. Zamiast tego
.?+
będziesz musiał pisać(?>.?)
.Jawa
.*
od którego możesz teraz zacząć lookahead(?<=(?=lookahead).*)
.\Q...\E
jak w Perlu / PCRE.Rubin
W najnowszych wersjach ten smak jest podobnie potężny jak PCRE, w tym obsługa wywołań podprogramów. Podobnie jak Java, obsługuje także łączenie i przecinanie klas znaków. Jedną specjalną cechą jest wbudowana klasa znaków dla cyfr szesnastkowych:
\h
(i negowanych\H
).Najbardziej przydatną funkcją gry w golfa jest sposób, w jaki Ruby obsługuje kwantyfikatory. Przede wszystkim można zagnieżdżać kwantyfikatory bez nawiasów.
.{5,7}+
działa i tak działa.{3}?
. Ponadto, w przeciwieństwie do większości innych smaków, jeśli dolną granicę kwantyfikatora0
można pominąć, np..{,5}
Jest równoważna.{0,5}
.Jeśli chodzi o podprogramy, główną różnicą między podprogramami PCRE i podprogramami Ruby jest to, że składnia Ruby jest dłuższa
(?n)
niż bajt\g<n>
, ale podprogramy Ruby mogą być używane do przechwytywania, podczas gdy PCRE resetuje przechwytywanie po zakończeniu podprogramu.Wreszcie, Ruby ma inną semantykę dla modyfikatorów związanych z linią niż większość innych smaków. Modyfikator, który jest zwykle wywoływany
m
w innych smakach, jest zawsze włączony w Ruby. Tak^
i$
zawsze dopasować początek i koniec linii , nie tylko na początku i na końcu łańcucha. To może zaoszczędzić bajt, jeśli trzeba to zachowanie, ale będzie cię to kosztować dodatkowe bajty, jeśli tego nie zrobisz, bo będziesz musiał wymienić^
i$
z\A
i\z
, odpowiednio. Oprócz tego w Ruby jest wywoływany zwykle modyfikators
(który powoduje.
dopasowanie linii)m
. Nie wpływa to na liczbę bajtów, ale należy o tym pamiętać, aby uniknąć pomyłek.Pyton
Python ma solidny smak, ale nie znam żadnych szczególnie użytecznych funkcji, których nigdzie indziej nie znajdziesz.
Jednakże , istnieje alternatywa smak , który jest przeznaczony do wymiany
re
modułu w pewnym momencie, a która zawiera wiele ciekawych funkcji. Oprócz dodania obsługi rekurencji, zmiennych długości znaków i operatorów kombinacji klas znaków, posiada także unikalną funkcję dopasowania rozmytego . Zasadniczo możesz określić liczbę dopuszczalnych błędów (wstawień, usunięć, podstawień), a silnik da ci przybliżone dopasowania.ECMAScript
Smak ECMAScript jest bardzo ograniczony i dlatego rzadko przydatny do gry w golfa. Jedyną rzeczą, do której się zmierza, jest negowana pusta klasa postaci,
[^]
która pasuje do dowolnej postaci, a także bezwarunkowo nieudana klasa pustych postaci[]
(w przeciwieństwie do zwykłej(?!)
). Niestety, smak nie ma żadnych cech, które sprawiają, że ten ostatni jest przydatny w przypadku normalnych problemów.Lua
Lua ma swój własny, unikalny smak, który jest dość ograniczony (np. Nie można nawet kwantyfikować grup), ale ma kilka przydatnych i interesujących funkcji.
%b
temu obsługuje bardzo kompaktową składnię w celu dopasowania zbalansowanych ciągów. Np.%b()
Dopasowuje a,(
a następnie wszystko do pasującego)
(poprawnie pomijając pary dopasowane wewnętrznie).(
i)
mogą tu być dowolne dwie postacie.Podnieść
Smak regexowy wzmocnienia jest zasadniczo Perlem. Ma jednak kilka fajnych nowych funkcji zastępowania wyrażeń regularnych, w tym zmiany wielkości liter i warunki warunkowe . O ile mi wiadomo, ta ostatnia jest wyjątkowa dla Boost.
źródło
.?+
równoważne z.*
?Poznaj swoje klasy postaci
Większość smaków wyrażeń regularnych ma predefiniowane klasy znaków. Na przykład
\d
dopasowuje cyfrę dziesiętną, która jest trzy bajty krótsza niż[0-9]
. Tak, mogą się nieznacznie różnić, ponieważ\d
mogą również pasować do cyfr Unicode w niektórych smakach, ale w przypadku większości wyzwań nie będzie to miało znaczenia.Oto niektóre klasy postaci występujące w większości odmian wyrażeń regularnych:
Ponadto mamy również:
które są negowanymi wersjami powyższego.
Pamiętaj, aby sprawdzić swój smak pod kątem ewentualnych dodatkowych klas postaci. Na przykład PCRE ma
\R
dla nowych linii i Lua ma nawet takie klasy, jak małe i wielkie litery.(Podziękowania dla @HamZa i @ MartinBüttner za zwrócenie na to uwagi)
źródło
\R
dla nowych linii w PCRE.Nie przejmuj się grupami, które nie przechwytują (chyba że ...)
Ta wskazówka dotyczy (przynajmniej) wszystkich popularnych smaków inspirowanych Perlem.
Może to być oczywiste, ale (gdy nie gra w golfa) dobrą praktyką jest używanie grup, które nie przechwytują,
(?:...)
gdy tylko jest to możliwe. Te dwie dodatkowe postacie?:
są jednak marnotrawstwem podczas gry w golfa, więc po prostu używaj grup przechwytywania, nawet jeśli nie zamierzasz ich odwoływać.Jest jednak jeden (rzadki) wyjątek: jeśli zdarzy ci się
10
co najmniej 3 razy utworzyć grupę odwołań wstecznych , możesz faktycznie zaoszczędzić bajty, przekształcając wcześniejszą grupę w grupę nie przechwytującą, tak że wszystkie te\10
stają się\9
s. (Podobne sztuczki mają zastosowanie, jeśli używasz grupy11
co najmniej 5 razy itd.)źródło
$9
zamiast$10
lub$11
raz zapisuje jeden bajt. Przekształcenie$10
w$9
jeden wymaga?:
dwóch bajtów, więc będziesz potrzebować trzech$10
sekund, aby coś zapisać. Przekształcenie$11
w$9
wymaga dwóch?:
s, czyli czterech bajtów, więc potrzebujesz pięciu$11
s, aby coś zapisać (lub pięć$10
i$11
łącznie).Rekurencja do ponownego użycia wzoru
Garść smaków wspiera rekursję ( według mojej wiedzy , Perl, PCRE i Ruby). Nawet jeśli nie próbujesz rozwiązać problemów rekurencyjnych, ta funkcja pozwala zaoszczędzić wiele bajtów w bardziej skomplikowanych wzorach. Nie ma potrzeby nawiązywania połączenia z inną grupą (nazwaną lub numerowaną) w obrębie samej grupy. Jeśli masz pewien wzorzec, który pojawia się kilka razy w wyrażeniu regularnym, po prostu zgrupuj go i odnieś się do niego poza tą grupą. Nie różni się to od wywołania podprogramu w normalnych językach programowania. Więc zamiast
w Perl / PCRE możesz zrobić:
lub w Ruby:
pod warunkiem, że jest to pierwsza grupa (oczywiście możesz użyć dowolnego numeru w połączeniu rekurencyjnym).
Zauważ, że to nie to samo, co odwołanie wsteczne (
\1
). Odwołania wsteczne pasują dokładnie do tego samego ciągu, który grupa dopasowała ostatnim razem. Te wywołania podprogramów faktycznie ponownie oceniają wzorzec. Jako przykładsomeComplexPatternHere
weźmy długą klasę znaków:To by pasowało do czegoś podobnego
Należy pamiętać, że nie można tutaj używać odwołań wstecznych, zachowując zachowanie. Wsteczne nie powiedzie się na powyższy napis, bo
B
i0
i!
nie są takie same. Jednak w przypadku wywołań podprogramów wzorzec jest w rzeczywistości ponownie oceniany. Powyższy wzór jest całkowicie równoważny zPrzechwytywanie wywołań podprogramów
Jedna uwaga dla Perla i PCRE: jeśli grupa
1
w powyższych przykładach zawiera dalsze grupy, to wywołania podprogramów nie zapamiętają ich przechwytywania. Rozważ ten przykład:To nie będzie pasować
ponieważ po powrocie wywołań podprogramu nowe przechwytywanie grupy
2
jest odrzucane. Zamiast tego ten wzór pasowałby do tego ciągu:Różni się to od Ruby, gdzie rozmowy podprogramów zrobić zachowują swoje zrzuty, więc odpowiednik Ruby regex
(\w(\d):)\2 \g<1>\2 \g<1>\2
będzie pasować do pierwszego z powyższych przykładach.źródło
\1
dla Javascript. I PHP też (tak myślę).(..)\1
pasowałby,abab
ale zawodził, podczasabba
gdy(..)(?1)
pasowałby do tego drugiego. W rzeczywistości jest to wywołanie podprogramu w tym sensie, że wyrażenie jest stosowane ponownie, zamiast dosłownie dopasować to, co pasowało ostatnim razem.(?=a.b.c)(.[0_B!$]){3}d
Powodowanie niepowodzenia meczu
Kiedy używasz wyrażenia regularnego do rozwiązywania problemów obliczeniowych lub dopasowywania wysoce nieregularnych języków, czasami konieczne jest spowodowanie awarii gałęzi wzorca, niezależnie od tego, gdzie jesteś w ciągu. Naiwnym podejściem jest stosowanie pustego negatywnego spojrzenia w przyszłość:
Zawartość (pusty wzorzec) zawsze pasuje, więc negatywne spojrzenie w przód zawsze zawodzi. Najczęściej jednak jest o wiele prostsza opcja: wystarczy użyć znaku, o którym wiesz, że nigdy nie pojawi się na wejściu. Na przykład, jeśli wiesz, że dane wejściowe zawsze będą składały się wyłącznie z cyfr, możesz po prostu użyć
lub jakikolwiek inny nie cyfrowy, niemetatyczny znak powodujący awarię.
Nawet jeśli twój wkład może potencjalnie zawierać jakiekolwiek podciągi, istnieją krótsze sposoby niż
(?!)
. Dowolny smak, który pozwala na pojawienie się zakotwiczeń we wzorcu w przeciwieństwie do końca, może użyć jednego z następujących 2-znakowych rozwiązań:Zauważ jednak, że niektóre smaki będą traktowane
^
i$
jako dosłowne znaki w tych pozycjach, ponieważ oczywiście nie mają sensu jako kotwice.W smaku ECMAScript istnieje również dość eleganckie rozwiązanie 2-znakowe
Jest to pusta klasa postaci, która stara się upewnić, że następne znaki są jedną z tych w klasie - ale w klasie nie ma żadnych znaków, więc zawsze się to nie powiedzie. Zauważ, że to nie zadziała w żadnym innym smaku, ponieważ klasy postaci zwykle nie mogą być puste.
źródło
Zoptymalizuj swoje OR
Ilekroć masz 3 lub więcej alternatyw w swoim RegEx:
Sprawdź, czy nie ma wspólnego początku:
A może nawet wspólne zakończenie?
Uwaga: 3 to dopiero początek i odpowiada tej samej długości, 4+ zrobiłoby różnicę
Ale co, jeśli nie wszystkie mają wspólny przedrostek? (białe znaki dodano tylko dla przejrzystości)
Pogrupuj je, dopóki zasada 3+ ma sens:
Lub nawet uogólnij, jeśli entropia spełnia twój przypadek użycia:
^ w tym przypadku jesteśmy pewni, że nie otrzymamy żadnego
clue
lubcrown
slack
Ryan
To „według niektórych testów” również poprawia wydajność, ponieważ zapewnia kotwicę na początek.
źródło
aqua|aquamarine
→aqua(|marine)
lubaqua(marine)?
.Ten jest dość prosty, ale warto powiedzieć:
Jeśli zauważysz, że powtarzasz klasę postaci
[a-zA-Z]
, prawdopodobnie możesz po prostu użyć[a-z]
i dołączyći
(case- i nsensitive modyfikator) do wyrażenia regularnego.Na przykład w Ruby następujące dwa wyrażenia regularne są równoważne:
/[a-zA-Z]+\d{3}[a-zA-Z]+/
/[a-z]+\d{3}[a-z]/i
- 7 bajtów krótszychW tym przypadku inne modyfikatory mogą również skrócić całkowitą długość. Zamiast tego:
/(.|\n)/
który pasuje do DOWOLNEGO znaku (ponieważ kropka nie pasuje do nowej linii), użyj s Ingle-line modyfikatora
s
, co sprawia dot nowe linie meczu././s
- 3 bajty krótszeW Ruby istnieje mnóstwo wbudowanych klas postaci dla wyrażeń regularnych. Zobacz tę stronę i wyszukaj „Właściwości postaci”.
Doskonałym przykładem jest „Symbol waluty”. Według Wikipedii istnieje mnóstwo możliwych symboli walutowych, a umieszczenie ich w klasie postaci byłoby bardzo drogie (
[$฿¢₡Ð₫€.....
]), podczas gdy można dopasować dowolny z nich w 6 bajtach:\p{Sc}
źródło
s
modyfikator nie jest obsługiwany. :( Ale tam możesz użyć zastrzeżonej/[^]/
sztuczki JavaScript .(.|\n)
nawet nie działa w niektórych smakach, ponieważ.
często również nie pasuje do innych typów separatorów linii. Jednak zwyczajowym sposobem wykonania tego (bezs
)[\s\S]
są te same bajty, co(.|\n)
.Prosty parser języka
Możesz zbudować bardzo prosty parser z podobnym do RE
\d+|\w+|".*?"|\n|\S
. Żetony, które musisz dopasować, są oddzielone znakiem RE ”lub„.Za każdym razem, gdy silnik RE próbuje dopasować się do bieżącej pozycji w tekście, wypróbuje pierwszy wzorzec, a następnie drugi itd. Jeśli to się nie powiedzie (na przykład tutaj spacja), przechodzi dalej i ponownie próbuje dopasować . Porządek jest ważny. Jeśli umieściliśmy
\S
termin przed\d+
terminem,\S
pasowałby on pierwszy do dowolnej spacji, która złamałaby nasz parser.Moduł
".*?"
dopasowywania ciągów używa nie chciwego modyfikatora, więc dopasowujemy tylko jeden ciąg naraz. Jeśli twój RE nie ma niechcianych funkcji, możesz użyć"[^"]*"
ekwiwalentu.Przykład Python:
Przykład gry w golfa w Pythonie:
Możesz dostosować wzory i ich kolejność do języka, który chcesz dopasować. Ta technika działa dobrze dla JSON, podstawowego HTML i wyrażeń liczbowych. Był z powodzeniem używany wiele razy w Pythonie 2, ale powinien być na tyle ogólny, aby działać w innych środowiskach.
źródło
\K
zamiast pozytywnego wygląduPCRE i Perl obsługują sekwencję zmiany znaczenia
\K
, która resetuje początek dopasowania. Oznacza to,ab\Kcd
że Twój ciąg wejściowy musi zawierać,abcd
ale zgłoszone dopasowanie będzie tylkocd
.Jeśli używasz pozytywnego wyglądu za początkiem wzoru (co jest prawdopodobnie najbardziej prawdopodobnym miejscem), to w większości przypadków możesz
\K
zamiast tego użyć i zapisać 3 bajty:Jest to równoważne w większości celów, ale nie do końca. Różnice niosą ze sobą zarówno zalety, jak i wady:
(?<=ab*)
. Ale dzięki\K
niemu możesz postawić przed nim dowolny wzór! Takab*\K
działa To sprawia, że ta technika jest znacznie potężniejsza w przypadkach, w których ma zastosowanie.\K
tej części wyrażenia regularnego jest cofane, podobnie jak wszystko inne.Wada: jak zapewne wiesz, kilka dopasowań wyrażenia regularnego nie może się pokrywać. Często do obejścia tego ograniczenia używa się lookaroundów, ponieważ lookahead może sprawdzić poprawność części ciągu, która została już zużyta przez wcześniejsze dopasowanie. Więc jeśli chcesz dopasować wszystkie znaki, które nastąpiły,
ab
możesz użyć(?<=ab).
. Biorąc pod uwagę wkładto pasowałoby do drugiego
a
ic
. Nie można tego odtworzyć za pomocą\K
. Jeśli użyjeszab\K.
, dostaniesz tylko pierwsze dopasowanie, ponieważ terazab
nie ma na to spojrzenia.źródło
\K
sekwencji ucieczki w ramach asercji dodatniej, zgłoszony początek udanego dopasowania może być dłuższy niż koniec dopasowania.ababc
, nie ma sposobu, aby dopasować zarówno drugia
i tymc
z\K
. Dostaniesz tylko jeden mecz.\G
.
od ostatniego meczu był naprawdęa
.Dopasowanie dowolnej postaci
W smaku ECMAScript brakuje
s
modyfikatorów, które.
pasują do dowolnego znaku (w tym nowego wiersza). Oznacza to, że nie ma jednoznakowego rozwiązania pozwalającego na dopasowanie całkowicie dowolnych znaków. Standardowe rozwiązanie w innych smakach (gdys
z jakiegoś powodu nie chce się używać ) to[\s\S]
. Jednak ECMAScript jest tylko smak (według mojej wiedzy), które obsługuje pustych klas postaci, a więc ma znacznie krótszy alternatywy:[^]
. Jest to zanegowana pusta klasa postaci - oznacza to, że pasuje do dowolnej postaci.Nawet w przypadku innych smaków możemy nauczyć się z tej techniki: jeśli nie chcemy używać
s
(np. Ponieważ nadal musimy mieć zwykłe znaczenie.
w innych miejscach), nadal może istnieć krótszy sposób dopasowania zarówno znaków nowej linii, jak i znaków do wydruku, pod warunkiem, że jest jakiś znak, o którym wiemy, że nie pojawia się na wejściu. Powiedzmy, że przetwarzamy liczby rozdzielane znakami nowej linii. Następnie możemy dopasować dowolny znak[^!]
, ponieważ wiemy, że!
nigdy nie będzie on częścią ciągu. To oszczędza dwa bajty nad naiwnym[\s\S]
lub[\d\n]
.źródło
\N
oznacza dokładnie to, co.
oznacza poza/s
trybem, z wyjątkiem tego, że nie ma na niego wpływu tryb.Używaj grup atomowych i kwantyfikatorów dzierżawczych
Stwierdzono, że grupy (atomowych
(?>...)
) i zaborczy kwantyfikatorów (?+
,*+
,++
,{m,n}+
) często bardzo użyteczne do golfa. Dopasowuje ciąg i nie pozwala na późniejsze śledzenie. Będzie więc pasował tylko do pierwszego pasującego łańcucha, który zostanie znaleziony przez silnik regex.Na przykład: Aby dopasować ciąg o nieparzystej liczbie
a
na początku, po którym nie występują kolejnea
, możesz użyć:To pozwala ci używać takich rzeczy jak
.*
swobodne , a jeśli istnieje oczywiste dopasowanie, nie będzie innej możliwości dopasowania zbyt dużej lub zbyt małej liczby znaków, co może zepsuć twój wzór.W wyrażeniu regularnym .NET (które nie ma kwantyfikatorów dzierżawczych) możesz użyć tego, aby wyskoczyć w grupie 1 największą wielokrotność 3 (maksymalnie 30) razy (niezbyt dobrze golfa):
źródło
Zapomnij o przechwyconej grupie po podwyrażeniu (PCRE)
Dla tego wyrażenia regularnego:
Jeśli chcesz wyczyścić \ 2 po grupie 1, możesz użyć rekurencji:
Będzie pasował,
aa
podczas gdy poprzedni nie. Czasami możesz również użyć??
lub nawet?
zamiast{0}
.Może to być przydatne, jeśli często używałeś rekurencji, a niektóre odnośniki zwrotne lub grupy warunkowe pojawiły się w różnych miejscach wyrażenia regularnego.
Należy również pamiętać, że grupy atomowe są zakładane dla rekurencji w PCRE. Więc to nie pasuje do jednej litery
a
:Nie próbowałem tego jeszcze w innych smakach.
W przypadku lookaheads możesz w tym celu użyć podwójnych negatywów:
źródło
Wyrażenia opcjonalne
Czasami warto o tym pamiętać
jest w większości taki sam jak
Jest jednak niewielka różnica: w pierwszym przypadku grupa albo przechwytuje,
abc
albo wcale nie przechwytuje. Ten drugi przypadek spowodowałby bezwarunkowe niepowodzenie odniesienia wstecznego. W drugim wyrażeniu grupa będzie przechwytywaćabc
lub pusty ciąg znaków, przy czym w drugim przypadku bezwarunkowo dopasuje się odwołanie wsteczne . Aby naśladować to drugie zachowanie?
, musisz otoczyć wszystko inną grupą, co kosztowałoby dwa bajty:Używana wersja
|
jest również przydatna, gdy chcesz owinąć wyrażenie w inną formę grupy i nie przejmuj się przechwytywaniem:Wreszcie, ta sztuczka może być również zastosowana do niestrawności,
?
gdzie oszczędza bajt nawet w jego surowej postaci (a w konsekwencji 3 bajty w połączeniu z innymi formami grup):źródło
Wiele wyprzedzających, które zawsze pasują (.NET)
Jeśli masz co najmniej 3 konstrukcje lookahead, które zawsze pasują (do przechwytywania podwyrażeń), lub jeśli na lookahead znajduje się kwantyfikator, po którym następuje coś innego, więc powinny znajdować się w niekoniecznie przechwyconej grupie:
Są one krótsze:
gdzie
a
nie powinna być nazwa przechwyconej grupy. Nie możesz używać tego,|
by oznaczać to, co zwykleb
ic
bez dodawania kolejnej pary nawiasów.Niestety równoważenie grup w warunkach warunkowych wydawało się błędne, przez co w wielu przypadkach było bezużyteczne.
źródło