CodeKitHub
Türkçe
Regex’te açgözlü ve tembel eşleştirme: Deseniniz neden gereğinden fazla karakteri kapsıyor?

Regex’te açgözlü ve tembel eşleştirme: Deseniniz neden gereğinden fazla karakteri kapsıyor?

Yayın Tarihi 24 Tem 2026

Kalın etiketinin içeriğini almak için <b>.*</b> yazarsınız, bunu <b>Hello</b> üzerinde denersiniz, mükemmel şekilde çalışır. Ardından, aynı satırda iki kalın etiket içeren gerçek bir HTML dosyasında bunu çalıştırdığınızda — <b>Hello</b> and <b>World</b> — iki eşleşme yerine, her iki etiketi de kapsayan tek bir devasa eşleşme elde edersiniz. Bu, düzenli ifade motorunuzdaki bir hata değildir; *, + ve {n,m}’in varsayılan davranışıdır ve ne olduğunu anladığınızda tek karakterlik bir düzeltmeyle çözülebilir.

Neden .* beklediğinizden fazlasını yakalar?

Varsayılan olarak, düzenli ifadelerindeki nicelik belirleyiciler açgözlüdür.* “bazı karakterlerle eşleş” anlamına gelmez; “mümkün olduğunca çok karakterle eşleş, ardından desenin geri kalanı kesinlikle gerektirdiği takdirde geri çekil” anlamına gelir.

<b>.*</b> ile <b>Hello</b> and <b>World</b> arasındaki farkı adım adım inceleyelim:

  1. <b>, ilk <b> ile eşleşir.
  2. .*, dizenin geri kalanının tamamını tüketerek başlar — ikinci <b>World</b> dahil olmak üzere sonuna kadar her şeyi.
  3. Motor, eşleşmeyi tamamlamak için </b>’i bulması gerektiğinden, .*’in sonundan bir karakter bir karakter geriye doğru taramaya başlar.
  4. </b>’in sığabileceği ilk konum (sonundan geriye doğru taranırken), dizgedeki en sondaki </b>’tir — “mantıken” durması gereken ilk konum değildir.

Dolayısıyla eşleşme, <b>Hello</b> and <b>World</b> dizisinin tamamı olarak sonuçlanır; çünkü açgözlü eşleştirme her zaman mümkün olan en uzun dizgiyi önce dener ve kalıbın geri kalanının başarılı olması için sadece gerekli olduğu kadar küçültür.

Çözüm: ? ile niceleyiciyi tembel hale getirin

Bir niceleyicinin hemen arkasına ? eklemek, onu açgözlüden tembel (aynı zamanda “açgözlü olmayan” veya “isteksiz” olarak da adlandırılır) hale getirir: *?, +?, ??, {n,m}?.

Tembel bir niceleyici ise tam tersini yapar: mümkün olduğunca az karakterle eşleştirmeye başlar, ardından desenin geri kalan kısmı henüz başarılı olamıyorsa genişler.

Aynı dizeye karşı <b>.*?</b>:

  1. <b>, ilk <b> ile eşleşir.
  2. .*?, sıfır karakter ile eşleştirerek başlar.
  3. Motor şunu kontrol eder: </b> tam burada eşleşiyor mu? Hayır (şu anda “Hello…” kısmındayız, henüz </b> kısmında değiliz) — bu nedenle .*?’i tam olarak bir karakter genişletir ve tekrar kontrol eder.
  4. Bu işlem, .*? tam olarak Hello’i tüketene kadar karakter karakter tekrarlanır; bu noktada </b> hemen eşleşir.

Sonuç: <b>Hello</b> ve <b>World</b> iki ayrı eşleşme olarak geri döner; bu, etiket benzeri veya sınırlayıcı benzeri yapıları ayrıştırırken neredeyse her zaman istediğiniz şeydir.

Gerçekten açgözlü eşleştirme istediğiniz durumlar (bu sadece “yanlış varsayılan” değildir)

Açgözlü eşleştirme, dilde bir hata değildir — farklı, aynı derecede yaygın bir durum için doğrudur: bir şeyin en dıştaki sınırını eşleştirmek, içindeki en küçük birimi değil. JSON benzeri bir metin yığınında “ilk { ile son } arasındaki her şeyi” ayıklıyorsanız (örneğin, iç içe geçme durumuna bakılmaksızın bir nesnenin tamamını almak için), greedy tam olarak doğru seçimdir; oysa lazy, bunun yerine ilk iç } ’de durur ve size kesik, geçersiz bir parça verir.

Genel kural: tekrarlanan küçük, sınırlandırılmış parçalar için lazy (etiketler, tırnak içine alınmış dizeler, liste öğeleri); “dıştaki tüm aralığı al” için greedy.

Hızlı başvuru

Desen Davranış Ne zaman kullanılır
.*, .+, {n,m} Açgözlü — mümkün olan en uzun eşleşmeyi bulur En dıştaki aralığı istiyorsanız veya dizgede yalnızca bir eşleşme varsa
.*?, .+?, {n,m}? Tembel — mümkün olan en kısa eşleşmeyi bulur Birbirine benzeyen, sınırlayıcılarla ayrılmış birden fazla parça varsa ve her birini ayrı ayrı almak istiyorsanız

Bir kalıbın test dizesi yerine gerçek girdinizde aslında hangisini yaptığından emin değilseniz, canlı eşleşme vurgulamalı bir regex tester üzerinde çalıştırırsanız, eşleşmelerin anında vurgulanması sayesinde farkı hemen görebilirsiniz — açgözlü (greedy) yöntemde tek bir büyük vurgulanmış blok görürken, tembel (lazy) yöntemde birkaç ayrı blok görürsünüz; bu, karakter karakter incelemeye kıyasla genellikle daha hızlıdır.

← Blog'a Dön