
Regex ahne vs laisk sobitamine: miks su muster haarab liiga palju
Avaldatud 24. juuli 2026
Kirjutad <b>.*</b>, et haarata paksu kirja sildi sisu, testid seda <b>Hello</b> peal ja see töötab täiuslikult. Siis käivitad selle päris HTML-il, kus samal real on kaks paksu kirja silti — <b>Hello</b> and <b>World</b> — ja kahe vaste asemel saad ühe hiigelvaste, mis hõlmab mõlemat silti. See pole viga sinu regex-mootoris; see on *, + ja {n,m} vaikekäitumine, ning sellel on ühe märgi pikkune lahendus, kui tead, mis toimub.
Miks .* haarab rohkem, kui ootasid
Vaikimisi on regexi kvantifikaatorid ahned — .* ei tähenda “sobita mõned märgid”, see tähendab “sobita nii palju märke kui võimalik ja taandu ainult siis, kui ülejäänud muster seda absoluutselt nõuab.”
Käi läbi <b>.*</b> vastu <b>Hello</b> and <b>World</b> samm-sammult:
<b>sobib esimese<b>-ga..*alustab kogu ülejäänud stringi neelamisega — kõike kuni lõpuni, kaasa arvatud teine<b>World</b>.- Mootor peab siis leidma
</b>, et vaste lõpetada, nii et ta hakkab.*lõpust taganema ühe märgi kaupa. - Esimene koht (lõpust tagasi skaneerides), kus
</b>sobib, on stringi kõige viimane</b>— mitte esimene, kus ta “loogiliselt” peaks peatuma.
Nii et vaste lõpeb olemas terve <b>Hello</b> and <b>World</b>, sest ahne sobitamine proovib alati kõigepealt pikimat võimalikku stringi ja vähendab seda ainult nii vähe kui vajalik, et ülejäänud muster õnnestuks.
Lahendus: muuda kvantifikaator laisaks ?-ga
? lisamine kohe pärast kvantifikaatorit muudab selle ahnest laisaks (nimetatakse ka “mitte-ahneks” või “vastumeelseks”): *?, +?, ??, {n,m}?.
Laisk kvantifikaator teeb vastupidist: ta alustab nii väheste märkide sobitamisega kui võimalik, ning laieneb ainult siis, kui ülejäänud muster veel ei õnnestu.
<b>.*?</b> sama stringi vastu:
<b>sobib esimese<b>-ga..*?alustab nulli märgi sobitamisega.- Mootor kontrollib: kas
</b>sobib täpselt siin? Ei (oleme kohas “Hello…”, mitte veel</b>-s) — nii et ta laiendab.*?täpselt ühe märgi võrra ja kontrollib uuesti. - See kordub märk-märgi haaval, kuni
.*?on neelanud täpseltHello, mille juures</b>sobib kohe.
Tulemus: <b>Hello</b> ja <b>World</b> tulevad tagasi kahe eraldi vastena, mis on peaaegu alati see, mida tegelikult sildi- või eraldajataoliste struktuuride parsimisel tahtsid.
Millal tahad tegelikult ahnust (see pole lihtsalt “vale vaikeseade”)
Ahnus pole keeles viga — see on õige teistsuguse, sama levinud juhtumi jaoks: millegi kõige välimise piiri sobitamiseks, mitte selle sees oleva väikseima üksuse. Kui ekstraktid “kõike esimese { ja viimase } vahel” JSON-taolises tekstiplokis (näiteks kogu objekti haaramiseks olenemata pesastusest), on ahnus täpselt õige ning laiskus peatuks selle asemel esimese sisemise } juures, andes sulle katkestatud, kehtetu fragmendi.
Rusikareegel: laiskus korduvate väikeste eraldatud tükkide jaoks (sildid, jutumärkides stringid, nimekirja elemendid); ahnus “haara kogu välimine ulatus” jaoks.
Kiirviide
| Muster | Käitumine | Kasuta seda, kui |
|---|---|---|
.*, .+, {n,m} |
Ahne — sobitab pikima võimaliku | Tahad kõige välimist ulatust või stringis on vaid üks vaste |
.*?, .+?, {n,m}? |
Laisk — sobitab lühima võimaliku | Sul on mitu sarnast eraldatud tükki ja tahad igaüht eraldi |
Kui pole kindel, kumba muster su päris sisendil (mitte testistringil) tegelikult teeb, siis selle käivitamine reaalse mitme-vastega teksti peal regexi testijas koos elava vaste esiletõstuga muudab erinevuse koheselt nähtavaks — näed ühte hiigelsuurt esiletõstetud plokki ahnuse puhul versus mitut eraldi plokki laiskuse puhul, mis on tavaliselt kiirem kui märk-märgi haaval läbi mõtlemine.