İçeriğe geç
Toova
Tüm Araçlar

Her Geliştiricinin Bilmesi Gereken 10 Regex Hilesi

Toova

Düzenli ifadeler, ilk başta anlaşılmaz görünen ve sonra birden yerine oturan araçlardan biridir. Bir kez yerine oturduğunda, onları her yerde görmeye başlarsınız: girdi doğrulama, log ayrıştırma, ara-bul-değiştir hatları, URL yönlendirme. Ancak çoğu geliştirici yalnızca birkaç özelliği kullanır — karakter sınıfları, niceleyiciler, çapalar — ve şartnamenin geri kalanına dokunmadan bırakır.

Bu kılavuz, temellerin ötesine geçen on regex özelliğini ele alır. Her biri, daha basit desenlerin temiz bir şekilde çözemediği gerçek bir sorunu çözer. Tüm örnekler JavaScript sözdizimini kullanır; bu da herhangi bir ECMAScript uyumlu ortam için geçerlidir.

Bu makaledeki her deseni, tek bir kurulum kodu satırı yazmadan Toova Regex Tester kullanarak test edebilirsiniz.

1. Lookahead'ler: Tüketmeden Eşleştir

Bir lookahead, eşleşme motorunun bu karakterlerin ötesine geçmesine neden olmadan, geçerli konumdan sonra bir desenin eşleşmesi (veya eşleşmemesi) gerektiğini iddia eder. Eşleşen metin, lookahead'in kontrol ettiği şeyi içermez.

Pozitif lookahead sözdizimi: (?=...)

// Pozitif lookahead: "foo" yalnızca "bar" tarafından takip edildiğinde eşleşir
const re1 = /foo(?=bar)/;
re1.test('foobar'); // true
re1.test('foobaz'); // false

Negatif lookahead sözdizimi: (?!...)

// Negatif lookahead: "foo" "bar" tarafından takip EDİLMEDİĞİNDE eşleşir
const re2 = /foo(?!bar)/;
re2.test('foobaz'); // true
re2.test('foobar'); // false

Pratik bir kullanım: yakalanan değere sembolü dahil etmeden, yalnızca bir para birimi sembolü tarafından takip edildiğinde bir fiyat sayısıyla eşleştirme. Veya bir parolanın, basamağın nerede bulunması gerektiğini belirtmeden (?=.*\d) kullanarak en az bir basamak içerdiğini doğrulama.

Lookahead'ler sıfır genişliklidir — hiçbir karakter tüketmezler. Birden fazla bağımsız koşulu eş zamanlı olarak uygulamak için aynı konumda birden fazla lookahead'i üst üste yığabilirsiniz.

2. Lookbehind'ler: Önce Ne Geldiğini Kontrol Et

Bir lookbehind, lookahead'in aynasıdır: geçerli konumdan önceki metni eşleşmeye dahil etmeden kontrol eder.

Pozitif lookbehind sözdizimi: (?<=...)

// Pozitif lookbehind: "bar" yalnızca "foo" tarafından önündeyse eşleşir
const re3 = /(?<=foo)bar/;
re3.test('foobar'); // true
re3.test('bazbar'); // false

Negatif lookbehind sözdizimi: (?<!...)

// Negatif lookbehind: "bar" "foo" tarafından önünde DEĞİLSE eşleşir
const re4 = /(?<!foo)bar/;
re4.test('bazbar'); // true
re4.test('foobar'); // false

Lookbehind'ler ECMAScript 2018'de geldi ve tüm modern tarayıcılarda ve Node.js 10+ sürümünde desteklenir. Yaygın bir kullanım senaryosu: anahtarı eşleşmeye dahil etmeden name='ten sonraki her şeyi eşleştirerek name=Alice gibi bir anahtar-değer çiftinin değer kısmını çıkarmak.

Not: Lookahead'lerin aksine, JavaScript'teki lookbehind ifadeleri değişken uzunluktaki desenleri içeremez — lookbehind ifadesi sabit veya sınırlı bir maksimum uzunluğa sahip olmalıdır.

3. Adlandırılmış Yakalama Grupları: Kendiliğinden Belgeli Desenler

Standart yakalama gruplarına numarayla başvurulur: $1, $2, vb. Bir grup ekleyip kaldırdığınızda, sonraki tüm başvurular bozulur. Adlandırılmış gruplar, her gruba bir etiket eklemenize izin vererek bunu çözer.

const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const m = '2026-05-10'.match(dateRe);
console.log(m.groups.year);  // "2026"
console.log(m.groups.month); // "05"
console.log(m.groups.day);   // "10"

Adlandırılmış gruplar değiştirme dizgilerinde de $<name> aracılığıyla kullanılabilir:

// Desende adlandırılmış grup kullanarak geri başvuru
const quoteRe = /(?<q>['"]).*?\k<q>/;
quoteRe.test('"hello"'); // true
quoteRe.test('"hello''); // false

Grup adı geçerli bir JavaScript tanımlayıcısı olmalıdır. Grubun ne yakaladığını yansıtan açıklayıcı adlar kullanın — year, port, protocol — ve desenleriniz neredeyse kendiliğinden belgeli hale gelir. Yukarıda gösterildiği gibi, adlandırılmış bir gruba geri başvurmak için desenin içinde \k<name> da kullanabilirsiniz.

4. Açgözlü Olmayan Niceleyiciler: Minimum Eşleştir

Varsayılan olarak, niceleyiciler (*, +, ?) açgözlüdür — mümkün olduğunca çok karakterle eşleşirler. Niceleyiciden sonra ? eklemek onu açgözlü olmayan (tembel veya isteksiz olarak da adlandırılır) hale getirir ve mümkün olduğunca az karakterle eşleşir.

const html = '<a>click</a>';

// Açgözlü (varsayılan) — mümkün olan en uzun dizgiyle eşleşir
/<.+>/.exec(html)?.[0]; // '<a>click</a>'

// Açgözlü olmayan — mümkün olan en kısa dizgiyle eşleşir
/<.+?>/.exec(html)?.[0]; // '<a>'

Bu, HTML, XML veya aynı sınırlayıcının birden çok kez görünebildiği herhangi bir biçimi ayrıştırırken önemlidir. Açgözlü sürüm, tüm dizgi boyunca ilk açılıştan son kapanış etiketine kadar her şeyi yutar. Açgözlü olmayan sürüm ise ilk geçerli kapanış eşleşmesinde durur.

Aynı şey +? (bir veya daha fazla, tembel) ve ?? (sıfır veya bir, tembel) için de geçerlidir. Açgözlü olmayan niceleyiciler neyin eşleştirilebileceğini değiştirmez — birden fazla seçenek olduğunda hangi geçerli eşleşmenin seçileceğini değiştirir.

5. Felaket Niteliğindeki Geri İzlemeyi Önleme

Geri izleme, düzenli ifade motorlarının başarısız bir eşleşme girişiminden kurtulma yöntemidir — desen boyunca farklı bir yol denerler. Çoğu durumda bu görünmez ve hızlıdır. Ancak bazı desenler, motorun üstel olarak büyüyen sayıda yolu keşfetmesine neden olabilir ve mütevazı bir girdi dizgisi için bile bir Node.js sürecini dize getirir.

Klasik tehlikeli desen, aaaaab gibi bir dizgiye uygulanan (a+)+ gibi iç içe geçmiş niceleyicilerdir. Motor, eşleşme olmadığı sonucuna varmadan önce a karakterlerini iç ve dış gruplar arasında bölmenin her olası yolunu dener.

Atomik gruplar ((?>...)), motora bir grubun eşleştikten sonra geri izlememesini söyleyerek bunu önler. JavaScript atomik grupları doğal olarak desteklemez, ancak bir lookahead ile possessive davranışı taklit edebilirsiniz:

// Atomik grup olmadan — motor (\d+) içine geri çekilir
// Atomik grupla — (\d+) eşleştiğinde geri izlemeye izin verilmez
// JavaScript atomik grupları doğal olarak desteklemez,
// ancak bunları bir lookahead hilesiyle taklit edebilirsiniz:
const re5 = /(?=(\d+))\1(?!\d)/; // possessive \d++ taklidi

Daha güvenli bir genel kural: belirli bir nedeniniz olmadıkça, niceleyicileri doğrudan diğer niceleyicilerin içine yerleştirmekten kaçının. Desenleri ne ile eşleştiklerine dair daha kesin olacak şekilde yeniden yazın. Yeniden düzenleme yaparken iki eşdeğer desenin çıktısını yan yana karşılaştırmak için Text Diff aracını da kullanabilirsiniz.

6. Karakter Sınıfı Küme İşlemleri (Unicode v Bayrağı)

ECMAScript 2024, karakter sınıfları içinde küme işlemlerini etkinleştiren v bayrağını tanıttı. Bu, "ünlüler hariç tüm harfler" veya "ASCII olan büyük harfler" ifadesini hantal bir alternasyon yerine temiz bir sınıf tanımı olarak ifade etmenize olanak tanır.

// POSIX karakter sınıfı çıkarma JS'de yok,
// ancak Unicode kümeler modu (`v` bayrağı) küme işlemleri ekler:
const lettersNoVowels = /[a-z--[aeiou]]/v;
lettersNoVowels.test('b'); // true
lettersNoVowels.test('e'); // false

v bayrağı karakter sınıfları içinde üç işlemi destekler:

  • Çıkarma: [A--B] — A'da olup B'de olmayan karakterler
  • Kesişim: [A&&B] — hem A'da hem de B'de olan karakterler
  • Birleşim: [AB] — A veya B'de olan karakterler (standart karakter sınıflarıyla aynı)

Node.js 20+ ve tüm sürekli güncellenen tarayıcılar v bayrağını destekler. Bu, u bayrağının bir üst kümesidir — ikisini birleştirmeyin; özelliklerine ihtiyacınız olduğunda v bayrağını tek başına kullanın.

7. Sözcük Sınırları: Bütün Sözcük Eşleştirme

\b çapası, bir sözcük karakteri (\w) ile sözcük olmayan bir karakter arasındaki konumla eşleşir. Karakter tüketmez — yalnızca konumu iddia eder. Tersi olan \B, bir sözcük sınırı olmayan herhangi bir konumla eşleşir.

const sentence = 'cat concatenate';

// \b olmadan — "cat" "concatenate" içinde de bulundu
/cat/g.exec(sentence); // hem "cat" içindeki "cat" hem de "concatenate" içindeki ile eşleşir

// \b ile — yalnızca bütün sözcük "cat"
/\bcat\b/g.exec(sentence); // yalnızca bağımsız "cat" ile eşleşir
// \B tersidir: sınırda değil, sözcüğün içinde eşleşir
/\Bcat\B/.test('concatenate'); // true — "cat" sözcüğün içindedir

Sözcük sınırları, koddaki veya metindeki tanımlayıcıları aramada gereklidir. Bunlar olmadan, id adlı bir değişken aramak indexOf, invalid ve grid'i de bulur. Eşleşmeleri bağımsız geçişlerle sınırlamak için \bterm\b kullanın.

Önemli bir uyarı: \b, JavaScript'in sözcük karakteri tanımını ([a-zA-Z0-9_]) kullanır. Aksanlı karakterler ve Latin olmayan harfler sözcük olmayan karakterler olarak değerlendirilir. Unicode farkındalıklı sözcük sınırları için v bayrağını Unicode özellik sınıflarıyla birleştirin.

8. Çok Satırlı Mod: Satır Başına Çapalar

Varsayılan olarak, ^ yalnızca dizginin en başıyla ve $ yalnızca dizginin en sonuyla eşleşir. m (çok satırlı) bayrağı bunu değiştirir: ^ her satırın başıyla ve $ her satırın sonuyla eşleşir.

const text = 'line one\nline two\nline three';

// m bayrağı olmadan — ^ yalnızca tüm dizginin başıyla eşleşir
/^line/.test(text); // true (yalnızca ilk satır)

// m bayrağıyla — ^ HER satırın başıyla eşleşir
const matches = text.match(/^line/gm);
console.log(matches); // ['line', 'line', 'line']

Bu, log dosyaları, yapılandırma dosyaları veya kod gibi çok satırlı metinleri işlerken vazgeçilmezdir. Yaygın kullanımlar arasında bir anahtar sözcükle başlayan satırları çıkarma, satır sonu belirteçlerini değiştirme veya bir bloktaki her satırın bir desenle eşleştiğini doğrulama bulunur.

m bayrağını s bayrağıyla (dotAll) karıştırmayın. s bayrağı, .'nın yeni satır karakterleriyle de eşleşmesini sağlar. m bayrağı .'yı hiç etkilemez — yalnızca ^ ve $'ın davranışını etkiler.

9. Unicode Özellik Kaçışları: Uluslararası Karakter Eşleştirme

u bayrağı, karakterleri Unicode kategorilerine, yazı sistemlerine veya diğer özelliklerine göre eşleştirmenize olanak tanıyan Unicode özellik kaçışlarını etkinleştirir. Bu, yalnızca ASCII değil, tüm insan yazı sistemleri arasında harfleri, basamakları veya noktalama işaretlerini eşleştirmenin doğru yoludur.

// u bayrağı Unicode özellik kaçışlarını etkinleştirir
const letters = /\p{L}+/u;
letters.test('Héllo');   // true
letters.test('你好');    // true
letters.test('12345');   // false

// Tüm yazı sistemleri arasında yalnızca büyük harflerle eşleş
const upper = /\p{Lu}+/u;
upper.test('ABC');  // true
upper.test('abc');  // false
// Emoji ile eşleş (Unicode genel kategorisi: Sembol, Diğer)
const emoji = /\p{So}/u;
emoji.test('🚀'); // true

En yaygın kullanılan Unicode özellikleri şunlardır:

  • \p{L} — herhangi bir harf (tüm yazı sistemleri)
  • \p{Lu} — büyük harfler
  • \p{Ll} — küçük harfler
  • \p{N} — herhangi bir sayı
  • \p{Nd} — ondalık basamaklar
  • \p{P} — noktalama işaretleri
  • \p{Script=Latin} — Latin yazı sistemi karakterleri
  • \p{Emoji} — emoji karakterleri

Belirtilen özelliğe sahip olmayan her şeyi eşleştirerek olumsuzlamak için \P{...} (büyük P) kullanın. Desteklenen Unicode özelliklerinin ve değerlerinin tam listesi MDN belgelerinde tutulmaktadır.

10. Dizgi Birleştirme Yoluyla Ayrıntılı Desenler

Birçok regex çeşidi (Python, Ruby, .NET, PCRE) desenler içinde boşluk ve yorumlara izin veren ayrıntılı veya genişletilmiş bir modu (x bayrağı) destekler. JavaScript'in bu bayrağı yoktur — x bayrağı ECMAScript'te geçerli değildir.

Standart çözüm, desenleri adlandırılmış dizgi sabitlerinden oluşturmak ve bunları new RegExp() ile birleştirmektir:

// JavaScript'in yerel bir x bayrağı yok,
// ancak okunabilir desenleri dizgi sabitleri olarak oluşturabilirsiniz:
const YEAR  = '(?<year>\\d{4})';
const SEP   = '-';
const MONTH = '(?<month>\\d{2})';
const DAY   = '(?<day>\\d{2})';
const datePattern = new RegExp(YEAR + SEP + MONTH + SEP + DAY);

Her sabit neyle eşleştiğini açıklar ve son desen bir cümle gibi okunur. Bu yaklaşım ayrıca bir kod tabanındaki birden fazla regex tanımı arasında paylaşılan alt desenleri birleştirmeyi ve her bileşeni bağımsız olarak birim testi yapmayı kolaylaştırır.

Daha az karmaşık desenler için, tüm regex'i yakındaki bir blok yorumda satır içi yorumlarla tek bir satırda tutmak genellikle yeterlidir. Amaç, bir sonraki geliştiricinin (gelecekteki siz dahil) deseni bir kod çözücüden geçirmeden anlayabilmesini sağlamaktır.

Hepsini Bir Araya Getirme

Bu on teknik, "bu regex neden uç durumlarda başarısız oluyor?" yüzey alanının büyük bir bölümünü kapsar. Lookahead'ler ve lookbehind'ler, bağlamı tüketmeden iddia etmenizi sağlar. Adlandırılmış gruplar, yeniden düzenlemeler boyunca desenleri okunabilir tutar. Açgözlü olmayan niceleyiciler kazara aşırı eşleşmeyi önler. Unicode özellik kaçışları ASCII'nin ötesindeki girdileri işler.

Akıcılık oluşturmanın en iyi yolu, gerçek desenleri gerçek verilere karşı denemektir. Hızlıca yinelemek için Regex Tester'ı kullanın. Deseniniz farklılaştırma veya temizleme gerektiren çıktı ürettiğinde, Text Diff aracı çalıştırmalar arasında tam olarak neyin değiştiğini gösterir. Ve regex'iniz JSON ayrıştırıyorsa, JSON Formatter yapılandırılmış sonucu tarayıcıdan ayrılmadan incelemenizi sağlar.

Tüm JavaScript regex sözdizimi ve bayraklarının kapsamlı bir referansı için, MDN Regex Cheatsheet yer imlenecek en iyi tek sayfadır. Bir desendeki her bileşenin yerleşik açıklamasıyla etkileşimli desen hata ayıklaması için, regex101.com JavaScript modunu destekler.