Regular Expressions
Hebzuchtige en luie kwantificatoren
Zoeken…
parameters
quantifiers | Beschrijving |
---|---|
? | Overeenkomen met het voorgaande teken of subexpressie 0 of 1 keer (bij voorkeur 1). |
* | Overeenkomen met het voorgaande teken of subexpressie 0 of meer keer (zoveel mogelijk). |
+ | Overeenkomen met het voorgaande teken of subexpressie 1 of meer keer (zoveel mogelijk). |
{n} | Overeenkomen met het vorige teken of subexpressie precies n keer. |
{min,} | Overeenkomen met het vorige teken of subexpressie min of meer keer (zoveel mogelijk). |
{0,max} | Overeenkomen met het voorgaande teken of subexpressie maximaal of minder keer (zo dicht mogelijk bij max .). |
{min,max} | Overeenkomen met het voorgaande teken of subexpressie ten minste min keer, maar niet meer dan max keer (zo dicht mogelijk bij max .). |
Lazy Quantifiers | Beschrijving |
?? | Overeenkomen met het voorgaande teken of subexpressie 0 of 1 keer (bij voorkeur 0). |
*? | Overeenkomen met het vorige teken of subexpressie 0 of meer keer (zo weinig mogelijk). |
+? | Overeenkomen met het voorgaande teken of subexpressie 1 of meer keer (zo weinig mogelijk). |
{n}? | Overeenkomen met het vorige teken of subexpressie precies n keer. Geen verschil tussen hebzuchtige en luie versie. |
{min,}? | Overeenkomen met het vorige teken of subexpressie min of meer keer (zo dicht mogelijk bij min ). |
{0,max}? | Pas maximaal of minder vaak overeen met het voorgaande teken of de subuitdrukking (zo weinig mogelijk). |
{min,max}? | Overeenkomen met het voorgaande teken of subexpressie ten minste min keer, maar niet meer dan max keer (zo dicht mogelijk bij min ). |
Opmerkingen
gulzigheid
Een hebzuchtige kwantificeerder probeert het subpatroon altijd zo vaak mogelijk te herhalen voordat kortere wedstrijden worden verkend door terug te volgen.
Over het algemeen komt een hebzuchtig patroon overeen met de langst mogelijke string.
Standaard zijn alle kwantificatoren hebzuchtig.
Luiheid
Een luie (ook wel niet-greedy of onwillig) kwantificeerder altijd pogingen het subpatroon zo weinig vaak als mogelijk herhaald, verken meer gelijken door expansie.
Over het algemeen komt een lui patroon overeen met de kortst mogelijke string.
Toevoegen om kwantificeringen lui te maken ?
naar de bestaande kwantificeerder, bijv. +?
, {0,5}?
.
Concept van hebzucht en luiheid bestaat alleen in backtracking-motoren
Het idee van hebzuchtige / luie kwantificeerder bestaat alleen in backtracking regex-motoren. In niet-backtracking regex-engines of POSIX-compatibele regex-engines, specificeren kwantificatoren alleen de bovengrens en ondergrens van de herhaling, zonder op te geven hoe de match moet worden gevonden - deze motoren komen altijd overeen met de meest linkse langste string.
Hebzucht versus luiheid
Gegeven de volgende input:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
We zullen twee patronen gebruiken: een hebzuchtig: A.*Z
en een lui: A.*?Z
Deze patronen leveren de volgende overeenkomsten op:
-
A.*Z
levert 1 wedstrijd op:AlazyZgreeedyAlaaazyZ
(voorbeelden: Regex101 , Rubular ) -
A.*?Z
levert 2 wedstrijden op:AlazyZ
enAlaaazyZ
(voorbeelden: Regex101 , Rubular )
Focus eerst op wat A.*Z
doet. Wanneer het overeenkomt met de eerste A
, probeert de .*
, Hebzuchtig te zijn, vervolgens zoveel mogelijk te matchen .
als mogelijk.
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\________________________/
A.* matched, Z can't match
Omdat de Z
niet overeenkomt, moet de motor teruglopen en moeten .*
Dan één minder zijn .
:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\_______________________/
A.* matched, Z can't match
Dit gebeurt nog een paar keer, totdat het eindelijk zover is:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\__________________/
A.* matched, Z can now match
Nu kan Z
overeenkomen, dus het algemene patroon komt overeen met:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\___________________/
A.*Z matched
De aarzelende (luie) herhaling in A.*?Z
komt daarentegen als eerste overeen .
mogelijk, en dan meer nemen .
als nodig. Dit verklaart waarom het twee overeenkomsten vindt in de invoer.
Hier is een visuele weergave van wat de twee patronen overeenkwamen:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\____/l \______/l l = lazy
\_________g_________/ g = greedy
Voorbeeld gebaseerd op antwoord gemaakt door polygenelubricants .
De POSIX-standaard omvat niet de ?
operator, dus veel POSIX-regex-engines hebben geen luie matching. Hoewel refactoring, vooral met de "grootste truc ooit" , in sommige gevallen kan helpen bij het matchen, is de enige manier om echte luie matching te hebben, een motor te gebruiken die dit ondersteunt.
Grenzen met meerdere overeenkomsten
Wanneer u een invoer met goed gedefinieerde grenzen hebt en meer dan één overeenkomst in uw string verwacht, hebt u twee opties:
- Luie kwantificatoren gebruiken;
- Een ontkende tekenklasse gebruiken.
Stel je de volgende situatie voor:
Je hebt een eenvoudige sjabloon-engine, je wilt substrings zoals $[foo]
waarbij foo
elke string kan zijn. U wilt deze substring vervangen door alles op basis van het gedeelte tussen de []
.
U kunt zoiets als \$\[(.*)\]
Proberen en vervolgens de eerste opnamegroep gebruiken.
Het probleem hiermee is dat als je een string hebt zoals something $[foo] lalala $[bar] something else
je match zal zijn
something $[foo] lalala $[bar] something else
| \______CG1______/|
\_______Match______/
De opnamegroep is foo] lalala $[bar
die al dan niet geldig is.
Je hebt twee oplossingen
Luiheid gebruiken: in dit geval is
*
lui maken een manier om de juiste dingen te vinden. Dus je verandert je uitdrukking in\$\[(.*?)\]
Met behulp van een ontkende tekenklasse:
[^\]]
wijzigt u uw uitdrukking in\$\[([^\]]*)\]
.
In beide oplossingen is het resultaat hetzelfde:
something $[foo] lalala $[bar] something else
| \_/| | \_/|
\____/ \____/
Met de capture-groep respectievelijk foo
en bar
.
Het gebruik van een ontkende tekenklasse vermindert het probleem van de backtracking en kan uw CPU veel tijd besparen als het gaat om grote ingangen.