
Pohlepno naspram lijenog podudaranja u regexu: zašto vaš izraz zahvati previše
Objavljeno 24. srp 2026.
Napišete <b>.*</b> da uhvatite sadržaj podebljane oznake, testirate na <b>Hello</b> i savršeno radi. Zatim pokrenete isto na stvarnom HTML-u s dvije podebljane oznake u istom retku — <b>Hello</b> and <b>World</b> — i umjesto dva podudaranja dobijete jedno ogromno koje obuhvaća obje oznake. To nije greška u vašem regex engineu; to je zadano ponašanje znakova *, + i {n,m}, a ispravlja se dodavanjem samo jednog znaka čim shvatite što se zapravo događa.
Zašto .* zahvati više nego što očekujete
Kvantifikatori u regexu su prema zadanim postavkama pohlepni (greedy) — .* ne znači “podudari neki broj znakova”, nego “podudari što je više moguće znakova, a popuštaj samo ako ostatak izraza to apsolutno zahtijeva”.
Pratimo <b>.*</b> na nizu <b>Hello</b> and <b>World</b> korak po korak:
<b>se podudara s prvim<b>..*počinje tako što proguta cijeli ostatak niza — sve do kraja, uključujući i drugi<b>World</b>.- Engine zatim treba pronaći
</b>da završi podudaranje, pa počinje popuštati s kraja od.*znak po znak. - Prvo mjesto (gledajući unatrag od kraja) gdje
</b>odgovara jest posljednji</b>u nizu — ne onaj prvi na kojem bi “logično” trebao stati.
Zato ispadne da je cijelo podudaranje <b>Hello</b> and <b>World</b>, jer pohlepno podudaranje uvijek prvo pokušava najduži mogući niz i skraćuje ga tek onoliko koliko je nužno da ostatak izraza uspije.
Rješenje: učinite kvantifikator lijenim uz ?
Dodavanje ? odmah iza kvantifikatora prebacuje ga iz pohlepnog u lijeno (lazy) ponašanje (naziva se i “non-greedy” ili “reluctant”): *?, +?, ??, {n,m}?.
Lijeni kvantifikator radi suprotno: počinje podudaranjem što manjeg broja znakova, a širi se samo ako ostatak izraza još ne može uspjeti.
<b>.*?</b> na istom nizu:
<b>se podudara s prvim<b>..*?počinje podudaranjem nula znakova.- Engine provjerava: podudara li se
</b>upravo ovdje? Ne (nalazimo se na “Hello…”, još nismo došli do</b>) — pa proširi.*?za točno jedan znak i provjeri opet. - To se ponavlja znak po znak sve dok
.*?ne proguta točnoHello, a tada se</b>odmah podudari.
Rezultat: <b>Hello</b> i <b>World</b> vraćaju se kao dva odvojena podudaranja, što je gotovo uvijek ono što ste zapravo željeli pri parsiranju struktura sličnih oznakama ili razdjelnicima.
Kada zapravo želite pohlepno podudaranje (nije “samo pogrešna zadana postavka”)
Pohlepno ponašanje nije greška u jeziku — ono je ispravno za drugi, jednako čest slučaj: podudaranje vanjske granice nečega, a ne najmanje jedinice unutar toga. Ako izvlačite “sve između prve { i posljednje }” iz bloka teksta nalik JSON-u (recimo, da uhvatite cijeli objekt bez obzira na ugniježđenost), pohlepno je upravo ispravno, dok bi lijeno stalo na prvoj unutarnjoj } i vratilo skraćen, neispravan fragment.
Pravilo: lijeno za ponavljajuće male ograđene dijelove (oznake, navodnici, stavke liste); pohlepno za “zahvati cijeli vanjski raspon”.
Brzi pregled
| Uzorak | Ponašanje | Kada koristiti |
|---|---|---|
.*, .+, {n,m} |
Pohlepno — podudara najdulje moguće | Kad želite najšire naspram, ili u nizu postoji samo jedno podudaranje |
.*?, .+?, {n,m}? |
Lijeno — podudara najkraće moguće | Kad imate više sličnih ograđenih dijelova i želite svaki zasebno |
Ako niste sigurni što određeni izraz zapravo radi na vašim stvarnim podacima, a ne na testnom nizu, pokretanje na pravom tekstu s više podudaranja u regex testeru s isticanjem podudaranja uživo odmah pokaže razliku — vidjet ćete jedan ogroman istaknuti blok kod pohlepnog nasuprot nekoliko odvojenih kod lijenog, što je obično brže od razmišljanja znak po znak.