---
title: 'Düzenli İfadeler'
source: 'https://academia.sh/tr/kurslar/python-temelleri/duzenli-ifadeler'
course: 'Python Temelleri'
language: tr
updated: '2026-08-17T18:10:27+00:00'
license: 'CC BY-SA 4.0'
---

# Düzenli İfadeler

Örüntüdeki yedi açılış parantezinin ikisi yakalamaz ve geriye beş numaralı grup kalır; numara açılış parantezinin sırasına göre verilir, eşleşmeme bir istisna değil None'dır ve eşleşme nesnesi her grubun metnini, aralığını ve adını taşır.

Önceki ders bu kursun ölçtüğü son sözdizim biçimini geride bıraktı. Şimdiye kadar her ölçüm
dilin kendi protokollerini çağıran bir deyim ya da ifadeydi: `for`, `if`, `+`, `with`.

Bu dersin konusu ise dilin sözdizimi değildir. **Düzenli ifade (regular expression)** standart
kitaplığın sunduğu ayrı bir küçük dildir: örüntü bir dizgide yazılır, ayrı bir kural kümesine
göre yorumlanır ve sonuç bir **nesne** olarak geri döner. Örüntü eşleme algoritmalarının
kendisi — kaba kuvvet arama, karma tabanlı arama, önek tablolu arama — **Algoritmalar**
kursunun metin algoritmaları konusunda kuruldu ve burada tekrarlanmaz. Ölçülecek olan şey
başka: **eşleşme nesnesinin ne taşıdığı** ve örüntüdeki parantezlerin **hangi sırayla
numaralandığı**.

## Örüntüde Parantezin İki İşi

Bir örüntüde parantezin iki ayrı işi vardır ve ikisi aynı yazımla görünür. Birincisi
**gruplama**: içindeki parçayı tek bir birim yapar ki tekrar ya da seçim işleci ona
uygulanabilsin. İkincisi **yakalama**: eşleşen metni ayrıca saklar ve numaralar.

Sıradan parantez **her iki işi birden** yapar. `(?:` ile açılan parantez yalnız gruplar,
yakalamaz — numara almaz. `(?P<ad>` ile açılan parantez hem yakalar hem numarasının yanına
bir ad koyar.

Numaralama kuralı tek cümledir: **numara, açılış parantezinin soldan sağa sırasına göre
verilir.** İç içe parantezlerde bile dıştaki önce numaralanır, çünkü onun açılışı daha
soldadır. Kapanış sırası hiç bakılmaz.

## Grupların Numaralanması

Ölçüm bir ölçüm kaydı satırını çözen tek bir örüntü kurar: istasyon adı, yıl, isteğe bağlı ay,
değer ve birim. Örüntü hem adlı hem yakalamayan parantez içerir.

- **HD43** — Parantez sayıları örüntü dizgisinin kendisinden sayılır; numaralanan grup sayısı
  ise derlenmiş örüntünün kendi alanından okunur. İkisi ayrı kaynaktır ve birbirini
  doğrular.
- **HD44** — Kâhin örüntüyü yazan kurgudur: hangi parçanın hangi gruba düşmesi gerektiği
  önceden bilinir.
- **HD45** — Aralıklar eşleşme nesnesinden okunur, elle sayılmaz; **karakter** aralığıdır,
  bayt değil.
- **HD46** — İsteğe bağlı grup eşleşmediğinde `None` döner; bu bir hata değil, grubun
  katılmadığının bildirimidir.
- **HD47** — İç içe örüntü ölçümü yalnız numaralamayı sınamak için ayrı tutulur; başka hiçbir
  şey ölçmez.

```python
"""Yakalama gruplari: parantezlerin numaralanmasi ve eslesme nesnesinin tasidigi."""
import re

ORUNTU = r"(?P<istasyon>[a-z]+)-(\d{4})(?:-(\d{2}))?:\s*(-?\d+(?:[.,]\d+)?)\s*(°C|%)"
DERLI = re.compile(ORUNTU)

print(f"örüntüdeki açılış parantezi {ORUNTU.count('(')} | "
      f"yakalamayan parantez {ORUNTU.count('(?:')} | "
      f"adlı grup {ORUNTU.count('(?P<')} | numaralanan grup {DERLI.groups}")
print("ad -> numara:", DERLI.groupindex)

SATIRLAR = ("kuzey-2031: 12,5 °C", "yamac-2031-07: -3.5 °C",
            "ozet-2031: 88 %", "bozuk kayit")

print()
print(f"{'satır':<26s}{'eşleşti':<9s}{'aralık':<10s}{'son grup':>9s}   gruplar")
for s in SATIRLAR:
    e = DERLI.search(s)
    if e is None:
        print(f"  {s:<24s}{'hayır':<9s}{'-':<10s}{'-':>9s}   -")
    else:
        print(f"  {s:<24s}{'evet':<9s}{str(e.span()):<10s}"
              f"{e.lastindex:>9d}   {e.groups()}")

print()
e = DERLI.search(SATIRLAR[1])
print("ikinci satırın eşleşme nesnesi:")
print(f"  group(0) (tüm eşleşme): {e.group(0)!r}")
for i in range(1, DERLI.groups + 1):
    print(f"  group({i}): {e.group(i)!r}  aralık {e.span(i)}")
print(f"  adla erişim: {e.group('istasyon')!r} | "
      f"adlı grup sözlüğü: {e.groupdict()}")

print()
IC_ICE = re.compile(r"((\d{4})-(\d{2}))")
i = IC_ICE.search("yamac-2031-07: -3.5 °C")
print(f"iç içe örüntüde numaralanan grup {IC_ICE.groups}; "
      f"numara açılış parantezinin sırasına göre verilir:")
for n in range(1, IC_ICE.groups + 1):
    print(f"  group({n}) = {i.group(n)!r}")
```

```
örüntüdeki açılış parantezi 7 | yakalamayan parantez 2 | adlı grup 1 | numaralanan grup 5
ad -> numara: {'istasyon': 1}

satır                     eşleşti  aralık     son grup   gruplar
  kuzey-2031: 12,5 °C     evet     (0, 19)           5   ('kuzey', '2031', None, '12,5', '°C')
  yamac-2031-07: -3.5 °C  evet     (0, 22)           5   ('yamac', '2031', '07', '-3.5', '°C')
  ozet-2031: 88 %         evet     (0, 15)           5   ('ozet', '2031', None, '88', '%')
  bozuk kayit             hayır    -                 -   -

ikinci satırın eşleşme nesnesi:
  group(0) (tüm eşleşme): 'yamac-2031-07: -3.5 °C'
  group(1): 'yamac'  aralık (0, 5)
  group(2): '2031'  aralık (6, 10)
  group(3): '07'  aralık (11, 13)
  group(4): '-3.5'  aralık (15, 19)
  group(5): '°C'  aralık (20, 22)
  adla erişim: 'yamac' | adlı grup sözlüğü: {'istasyon': 'yamac'}

iç içe örüntüde numaralanan grup 3; numara açılış parantezinin sırasına göre verilir:
  group(1) = '2031-07'
  group(2) = '2031'
  group(3) = '07'
```

## Eşleşme Nesnesinin Taşıdığı

İlk satır aritmetiği veriyor: örüntüde **7** açılış parantezi var, **2**'si yakalamayan, geriye
**5** numaralanan grup kalıyor. Sayının biri örüntü dizgisinden, öbürü derlenmiş örüntüden
geldi ve tuttular. Adlı grubun numarası kaybolmuyor: `istasyon` adı **1** numaraya karşılık
geliyor. Ad bir takma addır, numaranın yerine geçmez.

İkinci tablo dört satırı çözüyor. Üçünde eşleşme var, birinde yok. Eşleşenlerin `gruplar`
sütunu beşerli demet veriyor ve isteğe bağlı ay grubu, ay yazılmamış satırlarda `None`
dönüyor. `None` burada bir hata değildir: grubun **katılmadığı** anlamına gelir ve boş
dizgiden ayrılır — boş dizgi "eşleşti ama içi boştu" demek olurdu.

Üçüncü blok eşleşme nesnesinin taşıdığı bilginin tamamını açıyor. `group(0)` **tüm eşleşmedir**
ve bir grup değildir; numaralar ondan sonra başlar. Her grup hem metnini hem **aralığını**
veriyor: `2031` kaydın **6**–**10** karakterleri arasında duruyor. Bu aralık, eşleşen metni
kaynağın içinde yerinden çıkarmadan işaret etmeye yarar.

Son blok numaralamayı kesinleştiriyor. İç içe örüntüde **3** grup var ve `group(1)` dıştaki
bütünü, `group(2)` yılı, `group(3)` ayı veriyor. Dıştaki parantez sonra kapanmasına rağmen
**önce** numaralanıyor, çünkü **önce açılıyor**.

## Aramanın Biçimleri

İkinci ölçüm aynı örüntüyü ayrı arama biçimleriyle çalıştırır ve eşleşmemenin ne ürettiğini
sınar.

- **HD48** — Üç arama biçimi **aynı** derlenmiş örüntüyle ve aynı satırlarla denenir; tek
  değişen çağrılan yöntemdir.
- **HD49** — Çoklu arama sayıları listenin uzunluğundan okunur; satır sayısı metnin kendi
  satırlarından sayılır.
- **HD50** — Eşleşmeme durumunda dönen değer doğrudan basılır; sonucun istisna olmadığı
  koşumla gösterilir.
- **HD51** — Konum ölçümü aynı içeriği bir kez dizgi, bir kez bayt dizisi olarak arar; fark
  yalnız içeriğin türünden gelir.

```python
"""Eslesme aramanin bicimleri, eslesmeme durumu ve dizgi ile bayt uzerinde konum."""
import re

ORUNTU = r"(?P<istasyon>[a-z]+)-(\d{4})(?:-(\d{2}))?:\s*(-?\d+(?:[.,]\d+)?)\s*(°C|%)"
DERLI = re.compile(ORUNTU)

DENEMELER = ("kuzey-2031: 12,5 °C", "  kuzey-2031: 12,5 °C",
             "kuzey-2031: 12,5 °C ek", "bozuk kayit")

print(f"{'satır':<28s}{'search':<9s}{'match':<8s}fullmatch")
for s in DENEMELER:
    d = [("evet" if a(s) else "hayır")
         for a in (DERLI.search, DERLI.match, DERLI.fullmatch)]
    print(f"  {repr(s):<26s}{d[0]:<9s}{d[1]:<8s}{d[2]}")

KAYITLAR = ("kuzey-2031: 12,5 °C\n"
            "yamac-2031-07: -3.5 °C\n"
            "ozet-2031: 88 %\n"
            "bozuk kayit\n"
            "guney-2032: 41 °C")

print()
bulunan = DERLI.findall(KAYITLAR)
yinelenen = list(DERLI.finditer(KAYITLAR))
print(f"metin satırı {len(KAYITLAR.splitlines())} | findall {len(bulunan)} | "
      f"finditer {len(yinelenen)} | findall öğesinin uzunluğu "
      f"{len(bulunan[0])} | grup sayısı {DERLI.groups}")
print("finditer aralıkları:", [e.span() for e in yinelenen])

print()
yok = DERLI.search("bozuk kayit")
print("eşleşmeyen aramanın sonucu:", yok, "| istisna fırlattı mı: hayır")
try:
    yok.group(0)
except AttributeError as e:
    print(f"sonuç üzerinde group çağrısı: {type(e).__name__} — "
          f"birinci dersin sınıflamasında program kusuru")

print()
print("değiştirme, grupları geri kullanır:")
print(" ", DERLI.sub(r"\g<istasyon>=\4\5", KAYITLAR).replace("\n", " | "))

print()
METIN = "kuzey yamaç: 12,5 °C"
HAM = METIN.encode("utf-8")
print(f"karakter {len(METIN)} | bayt {len(HAM)}")
print(f"dizgi üzerinde 'C' konumu {re.search(r'C', METIN).start()} | "
      f"bayt dizisi üzerinde {re.search(rb'C', HAM).start()}")
```

```
satır                       search   match   fullmatch
  'kuzey-2031: 12,5 °C'     evet     evet    evet
  '  kuzey-2031: 12,5 °C'   evet     hayır   hayır
  'kuzey-2031: 12,5 °C ek'  evet     evet    hayır
  'bozuk kayit'             hayır    hayır   hayır

metin satırı 5 | findall 4 | finditer 4 | findall öğesinin uzunluğu 5 | grup sayısı 5
finditer aralıkları: [(0, 19), (20, 42), (43, 58), (71, 88)]

eşleşmeyen aramanın sonucu: None | istisna fırlattı mı: hayır
sonuç üzerinde group çağrısı: AttributeError — birinci dersin sınıflamasında program kusuru

değiştirme, grupları geri kullanır:
  kuzey=12,5°C | yamac=-3.5°C | ozet=88% | bozuk kayit | guney=41°C

karakter 20 | bayt 22
dizgi üzerinde 'C' konumu 19 | bayt dizisi üzerinde 21
```

## Sayıların Okunması

İlk tablo üç arama biçimini ayırıyor. `search` örüntüyü **her yerde** arar ve dört satırın
üçünde buluyor. `match` yalnız **baştan** dener: önünde boşluk olan satırda başarısız oluyor.
`fullmatch` satırın **tamamının** eşleşmesini ister: sonunda fazladan metin olan satırda
başarısız oluyor. Aynı örüntü, aynı satır, üç ayrı yanıt — hangi soruyu sorduğunuza bağlı.

İkinci satır çoklu aramayı sayıyor: **5** satırlık metinde **4** eşleşme var ve `findall` ile
`finditer` aynı sayıyı veriyor. Fark taşıdıkları şeydedir. `findall` her eşleşme için **5**
uzunluğunda bir demet veriyor — yani yalnız grupların metnini; aralık ve ad bilgisi kayboluyor.
`finditer` ise eşleşme nesnelerinin kendisini veriyor ve aralıklar okunabiliyor. Grup varken
`findall` bir sadeleştirmedir ve sadeleştirdiği şey, önceki bölümde ölçülen bilginin tamamıdır.

Üçüncü blok eşleşmemenin ne olduğunu söylüyor: sonuç **`None`** ve **istisna yok**. Düzenli
ifade eşleşmemeyi bir hata saymaz, çünkü eşleşmeme beklenen bir sonuçtur. İstisna ancak
`None` üzerinde `group` çağrılırsa doğar ve o zaman gelen sınıf `AttributeError` olur —
birinci dersin sınıflamasında bir **program kusuru**, yani `except` ile ele alınacak değil,
sınamayla önlenecek bir şey. Arama sonucu kullanılmadan önce sınanır.

Değiştirme satırı grupların ikinci işini gösteriyor: yakalanan parçalar yerine konan metinde
**numarayla ya da adla** geri kullanılabiliyor. Eşleşmeyen satır olduğu gibi kalıyor.

Son iki satır bu kursun üçüncü dersine bağlanıyor. Aynı içerik dizgi olarak **20** karakter,
bayt dizisi olarak **22** bayt; aranan harfin konumu birinde **19**, ötekinde **21**. Düzenli
ifade dizgide **karakter**, bayt dizisinde **bayt** sayar. Örüntü ile arandığı şeyin türü aynı
olmalıdır ve dönen aralıklar o türün birimindedir.

## Özet

- Parantezin iki işi vardır: gruplama ve yakalama; `(?:` yalnız gruplar, `(?P<ad>` hem yakalar
  hem ad verir — örüntüdeki **7** açılış parantezinin **2**'si yakalamaz, geriye **5** grup kalır.
- Numara **açılış parantezinin sırasına** göre verilir; iç içe örüntüde dıştaki grup önce
  numaralanır ve `group(0)` bir grup değil, tüm eşleşmedir.
- Eşleşme nesnesi her grubun metnini, **aralığını** ve varsa adını taşır; katılmayan isteğe
  bağlı grup `None` döner ve bu boş dizgiden ayrı bir bildirimdir.
- `search`, `match` ve `fullmatch` aynı satırda ayrı yanıt verir; `findall` **5** öğelik
  demetler döndürüp aralık bilgisini düşürür, `finditer` eşleşme nesnesini korur.
- Eşleşmeme bir istisna değil `None`'dır; istisna ancak sınanmadan `group` çağrılırsa doğar ve
  `AttributeError` olarak gelir.

## Kurs Kapanışı

Bu kurs tek bir iddiayı on altı derste ölçtü: **Python'da sözdizim bir kısaltmadır.** Yazılan
her biçim, adı belli bir **özel yöntemi** ya da adı belli bir kuralı çağırır; bir dersin sayısı,
anlattığı sözdizimin hangi protokolü kaç kez çağırdığıdır.

| ders | anlatılan sözdizim | çağrılan protokol |
|---|---|---|
| Python'un Yürütme Modeli | on bir sözdizim biçimi | 12 özel yöntem, toplam 18 çağrı |
| Sözdizim ve Girinti | girinti, blok, deyim ve ifade | özel yöntem yok: girinti birimleri ve ağaç |
| Değişkenler ve Veri Tipleri | ad bağlama, `x += ek` | `__add__` ile `__iadd__` ayrımı, nesne kimliği |
| İşleçler | `n + m`, `n += m`, `x in n` | `__add__`, `__iadd__`, `__contains__` yoksa `__iter__` |
| Dizgilerle Çalışma | dizgi yöntemleri ve biçimlendirme yazımları | `__format__`, `__str__`, `__repr__`; değiştirilemezlik yeni nesne kurdurur |
| Tip Dönüşümü |  |  |
| Koşullar | `if n` | `__bool__`, yoksa `__len__`, o da yoksa doğru |
| Döngüler | `for x in n` | `__iter__` ve `__next__`; bitişi `StopIteration` verir |
| Fonksiyon Tanımı | `def`, varsayılan değer, argüman biçimleri | varsayılan tanım anında bir kez değerlendirilir |
| Kapsam Kuralları | ad okuma ve atama | yerel, kapsayan, genel, yerleşik dört düzeyli arama |
| Yerleşik Fonksiyonlar |  |  |
| İstisnalar | `try`, `except`, `raise`, `finally` | istisna hiyerarşisi; yakalama sınıf soyağacına bakar |
| Özel İstisnalar | `class ...(Exception)` | sınıfın hiyerarşideki yeri yakalama davranışını belirler |
| Dosya İşlemleri | `open` metin kipi ve ikili kip | kodlama çözücüsü ve satır sonu çevirisi |
| Bağlam Yöneticileri | `with n` | `__enter__`, `__exit__` ve dönüş değerinin yutma kararı |
| Düzenli İfadeler | örüntü, grup, değiştirme | eşleşme nesnesi ve yakalama grubu numaralaması |

Tablonun boş satırları, bu ders yazıldığı sırada diskte bulunmayan derslerdir; onlar için
satır uydurulmadı.

İkinci sütunla üçüncü sütun arasındaki mesafe kursun bütün bulgusudur. Aynı görünen iki
yazım ayrı protokol çağırır — `n + m` ile `n += m` gibi. Aynı yazım, nesneye göre ayrı
protokol çağırır — `if n` gibi. Ve bir protokolün **başarısız olması** da protokolün
parçasıdır: döngüyü `StopIteration` bitirir, `with` bloğundaki istisnayı `__exit__` görür ve
dönüş değeriyle onu yutup yutmayacağına karar verir.

Buradan çıkan son okuma şudur: **bir nesnenin ne yapabildiği, tanımladığı özel yöntemlerle
belirlenir; tipinin adıyla değil.** Kurs boyunca ölçülen nesne hiçbir yerleşik koleksiyondan
inmedi; `for` içine girebilmesinin, `in` ile sınanabilmesinin, `with` bloğunda
kullanılabilmesinin tek gerekçesi ilgili yöntemleri **tanımlamış** olmasıydı.

Bu kurs boyunca protokoller hep **kullanıldı**. Bir sonraki kurs olan **Veri Yapıları ve
Fonksiyonel Araçlar** işin öteki yarısını alır: protokolü **yazmak**. İkisi ayrı şeylerdir.
`for` yazan biri yineleme protokolünün çağıranıdır; kendi yineleyicisini, kendi üretecini,
kendi sıralama ölçütünü yazan biri ise protokolün **karşı tarafını** kurar. Listeler, demetler,
sözlükler ve kümeler orada birer veri yapısı olarak değil, birer **protokol gerçekleştirimi**
olarak ele alınır — ve kendi nesnenizi onların yerine geçirebilmenizin koşulu, bu kursta
sayılan yöntemleri kendinizin tanımlamasıdır.
