
Regex mantkārīga pret slinku atbilstību: kāpēc jūsu šablons sagrābj pārāk daudz
Publicēts 2026. g. 24. jūl.
Jūs uzrakstāt <b>.*</b>, lai sagrābtu treknraksta taga saturu, testējat to uz <b>Hello</b>, tas strādā perfekti. Tad palaižat to uz reālu HTML ar diviem treknraksta tagiem vienā rindā — <b>Hello</b> and <b>World</b> — un divu atbilstību vietā iegūstat vienu milzīgu atbilstību, kas aptver abus tagus. Tā nav kļūda jūsu regex dzinējā; tā ir noklusējuma izturēšanās simboliem *, + un {n,m}, un tai ir viena rakstzīme garš labojums, tiklīdz saprotat, kas notiek.
Kāpēc .* sagrābj vairāk, nekā gaidāt
Pēc noklusējuma kvantifikatori regex ir mantkārīgi (greedy) — .* nenozīmē “atbilst dažām rakstzīmēm”, tas nozīmē “atbilst pēc iespējas vairāk rakstzīmēm un atkāpjas tikai tad, ja pārējais šablons to absolūti pieprasa”.
Izejiet cauri <b>.*</b> pret <b>Hello</b> and <b>World</b> soli pa solim:
<b>atbilst pirmajam<b>..*sāk, patērējot visu atlikušo virknes daļu — visu līdz pat beigām, ieskaitot arī otro<b>World</b>.- Dzinējam pēc tam jāatrod
</b>, lai pabeigtu atbilstību, tāpēc tas sāk atkāpties no.*beigām pa vienai rakstzīmei. - Pirmā vieta (skenējot atpakaļ no beigām), kur iederas
</b>, ir pati pēdējā</b>virknē — nevis pirmā, kurā tam “loģiski” vajadzētu apstāties.
Tātad atbilstība kļūst par <b>Hello</b> and <b>World</b> kopumā, jo mantkārīga atbilstība vienmēr vispirms mēģina garāko iespējamo virkni un samazina to tikai tik, cik nepieciešams, lai pārējais šablons izdotos.
Labojums: padarīt kvantifikatoru slinku ar ?
Pievienojot ? uzreiz aiz kvantifikatora, tas no mantkārīga pārtop par slinku (lazy) (dēvē arī par “nemantkārīgu” jeb “nevēlīgu”): *?, +?, ??, {n,m}?.
Slinks kvantifikators dara pretējo: tas sāk, atbilstot pēc iespējas mazākam rakstzīmju skaitam, un paplašinās tikai tad, ja pārējais šablons vēl nevar izdoties.
<b>.*?</b> pret to pašu virkni:
<b>atbilst pirmajam<b>..*?sāk, atbilstot nullei rakstzīmju.- Dzinējs pārbauda: vai
</b>atbilst tieši šeit? Nē (mēs esam pie “Hello…”, vēl neesam pie</b>) — tāpēc tas paplašina.*?par tieši vienu rakstzīmi un pārbauda vēlreiz. - Tas atkārtojas rakstzīmi pa rakstzīmei, līdz
.*?ir patērējis tiešiHello, un tajā brīdī</b>atbilst uzreiz.
Rezultāts: <b>Hello</b> un <b>World</b> tiek atgriezti kā divas atsevišķas atbilstības, kas gandrīz vienmēr ir tas, ko faktiski vēlējāties, parsējot tagiem vai atdalītājiem līdzīgas struktūras.
Kad faktiski vēlaties mantkārīgu (tas nav vienkārši “nepareizais noklusējums”)
Mantkārība nav valodas kļūda — tā ir pareiza citam, tikpat izplatītam gadījumam: atrast kaut kā ārējo robežu, nevis mazāko vienību iekšpusē. Ja izgūstat “visu starp pirmo { un pēdējo }” JSON līdzīga teksta blokā (teiksim, lai sagrābtu veselu objektu neatkarīgi no ligzdojuma), mantkārīgs ir tieši pareizi, un slinks apstātos pie pirmā iekšējā }, dodot jums nogrieztu, nederīgu fragmentu.
Īkšķa likums: slinks atkārtotiem maziem norobežotiem fragmentiem (tagi, citētas virknes, saraksta vienumi); mantkārīgs, lai “sagrābtu visu ārējo diapazonu”.
Ātra atsauce
| Šablons | Izturēšanās | Izmantojiet, kad |
|---|---|---|
.*, .+, {n,m} |
Mantkārīgs — atbilst garākajam iespējamajam | Vēlaties ārējo diapazonu vai virknē ir tikai viena atbilstība |
.*?, .+?, {n,m}? |
Slinks — atbilst īsākajam iespējamajam | Jums ir vairāki līdzīgi norobežoti fragmenti un vēlaties katru atsevišķi |
Ja neesat pārliecināts, ko šablons faktiski dara uz jūsu reālajiem datiem, nevis testa virknē, tā palaišana pret reālu, vairākas atbilstības saturošu tekstu regex testētājā ar tiešraides izcelšanu padara atšķirību uzreiz redzamu — redzēsiet vienu milzīgu izceltu bloku mantkārīgam salīdzinājumā ar vairākiem atsevišķiem slinkam, kas parasti ir ātrāk nekā domāt cauri rakstzīmi pa rakstzīmei.