← Kursa Dön
📄 Text · 18 min

Regular Expressions (re)

Giriş: Metin Arama Süper Gücü

Elinde 10.000 satırlık bir log dosyası var. İçinden sadece hatalı isteklerin IP adreslerini bulmak istiyorsun. Ya da bir formdan gelen email adreslerinin gerçekten geçerli olup olmadığını kontrol etmek istiyorsun. Ya da bir metindeki tüm telefon numaralarını bulmak...

Bu tür metin işleme görevleri için if "x" in text yetmez. Daha güçlü bir araca ihtiyacın var. İşte Regular Expressions (düzenli ifadeler, kısaca regex) bu araç.

Analoji: Metin Dedektifi

Regex'i bir dedektifin profil çizimi gibi düşün. Dedektif diyor ki: "Şüpheli 3 rakamla başlıyor, ardından bir tire geliyor, sonra 4 rakam var." Bu profil çizimine uyan tüm "şüpheliler" (metinler) yakalanır. Regex de tam olarak böyle çalışır — bir pattern (kalıp) tanımlarsın, Python o kalıba uyan tüm metinleri bulur.


re Modülü: Temel Fonksiyonlar

Python'da regex işlemleri re modülü ile yapılır.

import re

re.search(): İlk Eşleşmeyi Bul

import re

text = "Bugün hava 25 derece, yarın 28 derece olacak"
match = re.search(r"\d+", text)

if match:
    print(match.group())  # 25 (ilk bulunan sayı)
    print(match.start())  # 11 (başlangıç indeksi)
    print(match.end())    # 13 (bitiş indeksi)
    print(match.span())   # (11, 13) (başlangıç, bitiş)

r"\d+" ifadesindeki r prefix'i raw string demek. Backslash'lerin Python tarafından yorumlanmasını engeller. Regex yazarken her zaman r"" kullan.

re.match(): Sadece Başlangıçta Ara

# match() sadece string'in BAŞINDA arar
text = "Python 3.12 harika"

match = re.match(r"Python", text)
print(match.group() if match else "Yok")  # Python

match = re.match(r"harika", text)
print(match.group() if match else "Yok")  # Yok (başta değil!)

re.findall(): Tüm Eşleşmeleri Bul

text = "Ali 25 yaşında, Veli 30 yaşında, Ayşe 22 yaşında"
numbers = re.findall(r"\d+", text)
print(numbers)  # ['25', '30', '22']

findall() en sık kullanacağın fonksiyon. Tüm eşleşmeleri bir liste olarak döner.

re.finditer(): Eşleşmeleri Iterator Olarak Al

text = "Python 3.12 ve Java 21 ve Go 1.21"
for match in re.finditer(r"\d+\.?\d*", text):
    print(f"Bulundu: {match.group()} pozisyon: {match.span()}")
# Bulundu: 3.12 pozisyon: (7, 11)
# Bulundu: 21 pozisyon: (20, 22)
# Bulundu: 1.21 pozisyon: (29, 33)

Büyük metinlerde findall() yerine finditer() tercih et — bellek dostu çalışır.

re.sub(): Bul ve Değiştir

text = "Bugün 25 derece, yarın 28 derece"
result = re.sub(r"\d+", "XX", text)
print(result)  # Bugün XX derece, yarın XX derece

# Fonksiyon ile değiştirme
def celsius_to_fahrenheit(match):
    celsius = int(match.group())
    return str(int(celsius * 9/5 + 32))

result = re.sub(r"\d+", celsius_to_fahrenheit, text)
print(result)  # Bugün 77 derece, yarın 82 derece

re.split(): Pattern ile Böl

text = "Ali,Veli;Ayşe:Mehmet"
parts = re.split(r"[,;:]", text)
print(parts)  # ['Ali', 'Veli', 'Ayşe', 'Mehmet']

# Birden fazla boşlukla böl
text = "Python   Java    Go   Rust"
words = re.split(r"\s+", text)
print(words)  # ['Python', 'Java', 'Go', 'Rust']

Temel Pattern'ler

Meta Karakterler

KarakterAnlamÖrnekEşleşir
.Herhangi bir karakter (\n hariç)a.cabc, a1c, a-c
*0 veya daha fazla tekrarab*cac, abc, abbc
+1 veya daha fazla tekrarab+cabc, abbc (ac değil!)
?0 veya 1 tekrarcolou?rcolor, colour
[]Karakter kümesi[aeiou]a, e, i, o, u
()Grup(ab)+ab, abab, ababab
`\`VEYA`cat\dog`cat, dog
^Satır başı^Hello"Hello..."
$Satır sonuworld$"...world"
\Escape\.. (literal nokta)

Pratik Örnekler

import re

# . (herhangi karakter)
print(re.findall(r"p.t", "pat pet pit pot put"))
# ['pat', 'pet', 'pit', 'pot', 'put']

# * (0 veya daha fazla)
print(re.findall(r"go*gle", "ggle gogle google gooogle"))
# ['ggle', 'gogle', 'google', 'gooogle']

# + (1 veya daha fazla)
print(re.findall(r"go+gle", "ggle gogle google gooogle"))
# ['gogle', 'google', 'gooogle']  — ggle YOK

# ? (0 veya 1)
print(re.findall(r"colou?r", "color colour"))
# ['color', 'colour']

# | (VEYA)
print(re.findall(r"cat|dog", "I have a cat and a dog"))
# ['cat', 'dog']

# ^ ve $
print(re.search(r"^Python", "Python is great"))   # Match
print(re.search(r"^Python", "I love Python"))      # None
print(re.search(r"great$", "Python is great"))     # Match

Karakter Sınıfları

Önceden Tanımlı Sınıflar

PatternAnlamEşdeğer
\dRakam[0-9]
\DRakam olmayan[^0-9]
\wKelime karakteri[a-zA-Z0-9_]
\WKelime karakteri olmayan[^a-zA-Z0-9_]
\sBoşluk[ \t\n\r\f\v]
\SBoşluk olmayan[^ \t\n\r\f\v]
\bKelime sınırı(özel)
text = "Tarih: 2024-01-15, Fiyat: $99.50, Kod: ABC-123"

# \d — rakamlar
print(re.findall(r"\d+", text))
# ['2024', '01', '15', '99', '50', '123']

# \w — kelime karakterleri
print(re.findall(r"\w+", text))
# ['Tarih', '2024', '01', '15', 'Fiyat', '99', '50', 'Kod', 'ABC', '123']

# \s — boşluklar
print(re.split(r"\s+", "Python   Java\tGo\nRust"))
# ['Python', 'Java', 'Go', 'Rust']

\b — Kelime Sınırı

text = "cat category caterpillar scattered"

# \b olmadan: her yerde "cat" bulur
print(re.findall(r"cat", text))
# ['cat', 'cat', 'cat', 'cat']

# \b ile: sadece bağımsız "cat" kelimesini bulur
print(re.findall(r"\bcat\b", text))
# ['cat']

# Kelime başında "cat"
print(re.findall(r"\bcat\w*", text))
# ['cat', 'category', 'caterpillar']

Özel Karakter Kümeleri

# [abc] — a, b veya c
print(re.findall(r"[aeiou]", "Hello World"))
# ['e', 'o', 'o']

# [a-z] — küçük harfler
# [A-Z] — büyük harfler
# [0-9] — rakamlar
# [a-zA-Z] — tüm harfler

# [^abc] — a, b, c HARİCİ her şey
print(re.findall(r"[^aeiou\s]", "Hello World"))
# ['H', 'l', 'l', 'W', 'r', 'l', 'd']

# Özel karakterler [] içinde escape gerekmez (çoğu)
print(re.findall(r"[.!?]", "Merhaba! Nasılsın? İyi."))
# ['.', '!', '?'] — . burada literal nokta

Quantifier'lar: Tekrar Sayısı

Temel Quantifier'lar

PatternAnlamÖrnek
{n}Tam n kez\d{3} → 123
{n,}En az n kez\d{2,} → 12, 123, 1234
{n,m}n ile m arası\d{2,4} → 12, 123, 1234
*0+ (= {0,})a*
+1+ (= {1,})a+
?0 veya 1 (= {0,1})a?
# Tam 3 rakam
print(re.findall(r"\d{3}", "12 345 6789 01"))
# ['345', '678']

# 2 ile 4 arası rakam
print(re.findall(r"\d{2,4}", "1 22 333 4444 55555"))
# ['22', '333', '4444', '5555']

# Telefon numarası pattern'ı
text = "Tel: 0532-123-4567 veya 0555-987-6543"
phones = re.findall(r"\d{4}-\d{3}-\d{4}", text)
print(phones)  # ['0532-123-4567', '0555-987-6543']

Greedy vs Lazy Quantifier'lar

Bu konu çok önemli. Default olarak quantifier'lar greedy (açgözlü) — mümkün olan en uzun eşleşmeyi bulur.

text = "<b>kalın</b> ve <i>italik</i>"

# Greedy (default): .* mümkün olduğunca çok karakter yakalar
match = re.search(r"<.*>", text)
print(match.group())
# <b>kalın</b> ve <i>italik</i>  — Çok fazla yakaladı!

# Lazy: .*? mümkün olduğunca AZ karakter yakalar
match = re.search(r"<.*?>", text)
print(match.group())
# <b>  — Sadece ilk tag'ı yakaladı

# Tüm tag'ları bul (lazy)
print(re.findall(r"<.*?>", text))
# ['<b>', '</b>', '<i>', '</i>']

Lazy quantifier yapmak için ? eklersin:

  • *? → lazy *

  • +? → lazy +

  • ?? → lazy ?

  • {n,m}? → lazy {n,m}

⚠️ Dikkat: HTML/XML parse etmek için regex kullanma! Bunun için BeautifulSoup veya lxml gibi kütüphaneler var. Yukarıdaki örnek sadece greedy/lazy farkını göstermek için.


Gruplar: () ile Yakalama

Parantez () iki iş yapar:

  1. Pattern'leri gruplar (birlikte davranması için)

  2. Eşleşen kısmı yakalar (sonra erişebilirsin)

Temel Gruplama

# Gruplama: (ab)+ ile "ab" tekrarını ara
print(re.findall(r"(ab)+", "ababab cd abab"))
# ['ab', 'ab']  — findall() grup içeriğini döner!

# Tüm eşleşmeyi görmek için:
for m in re.finditer(r"(?:ab)+", "ababab cd abab"):
    print(m.group())
# ababab
# abab

Yakalama Grupları

# Tarih parse etme
text = "Tarih: 2024-01-15"
match = re.search(r"(\d{4})-(\d{2})-(\d{2})", text)

if match:
    print(match.group())   # 2024-01-15 (tüm eşleşme)
    print(match.group(1))  # 2024 (1. grup)
    print(match.group(2))  # 01 (2. grup)
    print(match.group(3))  # 15 (3. grup)
    print(match.groups())  # ('2024', '01', '15')

findall() ve Gruplar

# findall() grup varsa grup içeriklerini döner
text = "Ali:25, Veli:30, Ayşe:22"
pairs = re.findall(r"(\w+):(\d+)", text)
print(pairs)
# [('Ali', '25'), ('Veli', '30'), ('Ayşe', '22')]

for name, age in pairs:
    print(f"{name} → {age} yaşında")

Non-Capturing Group: (?:...)

Bazen gruplamak istiyorsun ama yakalamak istemiyorsun:

# Yakalayan grup
print(re.findall(r"(https?)://(\w+)", "http://google https://python"))
# [('http', 'google'), ('https', 'python')]

# Non-capturing grup
print(re.findall(r"(?:https?)://(\w+)", "http://google https://python"))
# ['google', 'python']  — sadece yakalayan grup döner

Named Groups: (?P<name>...)

Gruplara numara yerine isim verebilirsin. Kodu çok daha okunaklı yapar.

# Named group ile tarih parse etme
text = "Doğum tarihi: 1990-05-15"
pattern = r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})"
match = re.search(pattern, text)

if match:
    print(match.group("year"))   # 1990
    print(match.group("month"))  # 05
    print(match.group("day"))    # 15
    print(match.groupdict())     # {'year': '1990', 'month': '05', 'day': '15'}

Named Group ile sub()

# Tarih formatını değiştir: YYYY-MM-DD → DD/MM/YYYY
text = "Tarihler: 2024-01-15, 2024-06-30"
result = re.sub(
    r"(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})",
    r"\g<d>/\g<m>/\g<y>",
    text
)
print(result)
# Tarihler: 15/01/2024, 30/06/2024

Log Parser Örneği

log_line = '[2024-01-15 14:30:22] ERROR: Connection timeout (host=db.example.com)'

pattern = (
    r"\[(?P<timestamp>[\d-]+ [\d:]+)\] "
    r"(?P<level>\w+): "
    r"(?P<message>.+)"
)

match = re.search(pattern, log_line)
if match:
    data = match.groupdict()
    print(data)
    # {'timestamp': '2024-01-15 14:30:22', 'level': 'ERROR', 
    #  'message': 'Connection timeout (host=db.example.com)'}

re.compile(): Pattern'ı Önceden Derleme

Aynı pattern'ı birçok kez kullanacaksan, re.compile() ile önceden derle. Performans kazancı sağlar.

# Her seferinde derleme (yavaş)
for line in log_lines:
    match = re.search(r"\d{4}-\d{2}-\d{2}", line)

# Önceden derleme (hızlı)
date_pattern = re.compile(r"\d{4}-\d{2}-\d{2}")
for line in log_lines:
    match = date_pattern.search(line)

Compiled pattern nesnesi aynı metodlara sahip:

email_pattern = re.compile(r"[\w.+-]+@[\w-]+\.[\w.]+")

# search, findall, sub, split hepsi var
emails = email_pattern.findall("ali@gmail.com ve veli@hotmail.com")
print(emails)  # ['ali@gmail.com', 'veli@hotmail.com']

# match
result = email_pattern.match("test@example.com")
print(result.group())  # test@example.com

💡 İpucu: Python regex'leri zaten dahili olarak cache'ler (son 512 pattern). Ama açıkça compile() kullanmak kodu daha okunaklı yapar ve IDE desteği sağlar.


Flags: Regex Davranışını Değiştirme

re.IGNORECASE (re.I)

# Büyük/küçük harf farkını yok say
print(re.findall(r"python", "Python PYTHON python", re.IGNORECASE))
# ['Python', 'PYTHON', 'python']

# Kısa yazım
print(re.findall(r"python", "Python PYTHON python", re.I))
# ['Python', 'PYTHON', 'python']

re.MULTILINE (re.M)

text = """Birinci satır
İkinci satır
Üçüncü satır"""

# Default: ^ sadece string başı
print(re.findall(r"^\w+", text))
# ['Birinci']

# MULTILINE: ^ her satır başı
print(re.findall(r"^\w+", text, re.MULTILINE))
# ['Birinci', 'İkinci', 'Üçüncü']

re.DOTALL (re.S)

text = "Satır 1\nSatır 2\nSatır 3"

# Default: . newline'ı eşleştirmez
match = re.search(r"Satır 1.+Satır 3", text)
print(match)  # None

# DOTALL: . newline'ı da eşleştirir
match = re.search(r"Satır 1.+Satır 3", text, re.DOTALL)
print(match.group())  # Satır 1\nSatır 2\nSatır 3

re.VERBOSE (re.X) — Okunaklı Regex

# Karmaşık regex'i okunaklı yaz
email_pattern = re.compile(r"""
    ^                   # String başı
    [\w.+-]+            # Kullanıcı adı (harf, rakam, ., +, -)
    @                   # @ işareti
    [\w-]+              # Domain adı
    \.                  # Nokta
    [\w.]+              # TLD (.com, .co.uk vs.)
    $                   # String sonu
""", re.VERBOSE)

print(email_pattern.match("ali@gmail.com"))     # Match
print(email_pattern.match("geçersiz@"))         # None

Birden Fazla Flag

# Flag'leri | ile birleştir
pattern = re.compile(r"^hello\s+world$", re.IGNORECASE | re.MULTILINE)

Pratik: Email Validator

import re

def validate_email(email):
    """Email adresini doğrula."""
    pattern = re.compile(r"""
        ^                       # Başlangıç
        [a-zA-Z0-9._%+-]+      # Kullanıcı adı
        @                       # @ işareti
        [a-zA-Z0-9.-]+         # Domain
        \.                      # Nokta
        [a-zA-Z]{2,}           # TLD (en az 2 karakter)
        $                       # Bitiş
    """, re.VERBOSE)
    
    return bool(pattern.match(email))

# Test
test_emails = [
    "ali@gmail.com",          # ✅ Geçerli
    "veli.yilmaz@company.co", # ✅ Geçerli
    "test+tag@example.org",   # ✅ Geçerli
    "@gmail.com",             # ❌ Kullanıcı adı yok
    "ali@",                   # ❌ Domain yok
    "ali@gmail",              # ❌ TLD yok
    "ali gmail.com",          # ❌ @ yok
]

for email in test_emails:
    status = "✅" if validate_email(email) else "❌"
    print(f"{status} {email}")

Pratik: Telefon Numarası Parser

def parse_phone_numbers(text):
    """Metindeki telefon numaralarını bul ve normalize et."""
    pattern = re.compile(r"""
        (?:                     # Ülke kodu (opsiyonel)
            (?:\+90|0090)       # +90 veya 0090
            \s*                 # Boşluk (opsiyonel)
        )?
        \(?                     # Açık parantez (opsiyonel)
        (5\d{2})                # Operatör kodu: 5XX
        \)?                     # Kapalı parantez (opsiyonel)
        [\s.-]?                 # Ayırıcı (opsiyonel)
        (\d{3})                 # İlk 3 rakam
        [\s.-]?                 # Ayırıcı (opsiyonel)
        (\d{2})                 # Sonraki 2 rakam
        [\s.-]?                 # Ayırıcı (opsiyonel)
        (\d{2})                 # Son 2 rakam
    """, re.VERBOSE)
    
    results = []
    for match in pattern.finditer(text):
        op, p1, p2, p3 = match.groups()
        normalized = f"0{op} {p1} {p2} {p3}"
        results.append({
            "original": match.group(),
            "normalized": normalized
        })
    return results

# Test
text = """
Bana ulaşın: 0532-123-45-67
Alternatif: (555) 987 65 43
Yurtdışından: +90 542 111 22 33
Veya: 05301234567
"""

for phone in parse_phone_numbers(text):
    print(f"{phone['original']:>25} → {phone['normalized']}")

Pratik: Log Parser

def parse_log_file(log_text):
    """Log dosyasını parse et."""
    pattern = re.compile(r"""
        \[(?P<timestamp>\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})\]  # Tarih
        \s+
        (?P<level>DEBUG|INFO|WARNING|ERROR|CRITICAL)                # Seviye
        \s+
        (?P<module>[\w.]+)                                          # Modül
        \s*:\s*
        (?P<message>.+)                                             # Mesaj
    """, re.VERBOSE)
    
    entries = []
    for line in log_text.strip().split("\n"):
        match = pattern.search(line)
        if match:
            entries.append(match.groupdict())
    return entries

log_text = """
[2024-01-15 14:30:22] INFO app.server: Server started on port 8080
[2024-01-15 14:30:25] DEBUG app.db: Connected to database
[2024-01-15 14:31:00] ERROR app.auth: Authentication failed for user admin
[2024-01-15 14:31:05] WARNING app.cache: Cache miss for key user:123
[2024-01-15 14:32:00] CRITICAL app.server: Out of memory!
"""

entries = parse_log_file(log_text)
for entry in entries:
    print(f"[{entry['level']:>8}] {entry['module']}: {entry['message']}")

# Sadece hataları filtrele
errors = [e for e in entries if e["level"] in ("ERROR", "CRITICAL")]
print(f"\nToplam hata: {len(errors)}")

İleri Regex Teknikleri

Lookahead ve Lookbehind

Bunlar eşleşmeyi kontrol eder ama yakalamaz (zero-width assertions):

# Positive lookahead: (?=...) — sonrasında ... olan
# "Python" kelimesini bul AMA sadece sonrasında sayı varsa
text = "Python3 Python Java Python2"
print(re.findall(r"Python(?=\d)", text))
# ['Python', 'Python']  — Python3 ve Python2'deki "Python"

# Negative lookahead: (?!...) — sonrasında ... OLMAYAN
print(re.findall(r"Python(?!\d)", text))
# ['Python']  — sadece yalın "Python"

# Positive lookbehind: (?<=...) — öncesinde ... olan
text = "$100 €200 $300"
print(re.findall(r"(?<=\$)\d+", text))
# ['100', '300']  — $ işaretinden sonraki sayılar

# Negative lookbehind: (?<!...) — öncesinde ... OLMAYAN
print(re.findall(r"(?<!\$)\d+", text))
# ['200']  — $ ile başlamayan sayılar (€200'ün sayısı)

Backreference: Önceki Gruba Referans

# \1 ile ilk gruba referans: tekrar eden kelimeler bul
text = "Bu bu bir bir test test cümlesi"
duplicates = re.findall(r"\b(\w+)\s+\1\b", text, re.IGNORECASE)
print(duplicates)  # ['bu', 'bir', 'test'] — tekrar eden kelimeler

# HTML tag eşleştirme: açılış ve kapanış tag'ı aynı olmalı
text = "<b>kalın</b> <i>italik</i> <b>hatalı</i>"
valid_tags = re.findall(r"<(\w+)>.*?</\1>", text)
print(valid_tags)  # ['b', 'i'] — sadece eşleşen tag'lar

Koşullu Pattern

# Şifre gücü kontrolü: 
# En az 8 karakter, büyük harf, küçük harf, rakam, özel karakter
def check_password(password):
    checks = {
        "en az 8 karakter": r".{8,}",
        "büyük harf": r"[A-Z]",
        "küçük harf": r"[a-z]",
        "rakam": r"\d",
        "özel karakter": r"[!@#$%^&*(),.?\":{}|<>]"
    }
    
    results = {}
    for desc, pattern in checks.items():
        results[desc] = bool(re.search(pattern, password))
    return results

result = check_password("MyP@ss123")
for check, passed in result.items():
    status = "✅" if passed else "❌"
    print(f"{status} {check}")

Yaygın Regex Kalıpları

# IP adresi
ip_pattern = r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b"

# URL
url_pattern = r"https?://[\w.-]+(?:\.[\w]+)+(?:/[\w.-]*)*"

# Tarih (YYYY-MM-DD)
date_pattern = r"\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])"

# Hex renk kodu
hex_color_pattern = r"#(?:[0-9a-fA-F]{3}){1,2}\b"

# Türkçe TC Kimlik No (11 rakam, 0 ile başlamaz)
tc_pattern = r"\b[1-9]\d{10}\b"

Yaygın Hatalar

1. Raw String Kullanmamak

# YANLIŞ: \b Python'da backspace
print(re.findall("\btest\b", "this is a test"))  # []

# DOĞRU: r prefix ile raw string
print(re.findall(r"\btest\b", "this is a test"))  # ['test']

2. Greedy Tuzağı

# YANLIŞ: HTML tag'ları arasını yakala
html = "<p>Paragraf 1</p><p>Paragraf 2</p>"
print(re.findall(r"<p>(.*)</p>", html))
# ['Paragraf 1</p><p>Paragraf 2']  — Çok fazla yakaladı!

# DOĞRU: Lazy kullan
print(re.findall(r"<p>(.*?)</p>", html))
# ['Paragraf 1', 'Paragraf 2']

3. Özel Karakterleri Escape Etmemek

# YANLIŞ: . herhangi karakter demek
print(re.findall(r"example.com", "exampleXcom example.com"))
# ['exampleXcom', 'example.com']

# DOĞRU: \. literal nokta
print(re.findall(r"example\.com", "exampleXcom example.com"))
# ['example.com']

# re.escape() ile otomatik escape
user_input = "price is $10.00 (USD)"
safe = re.escape(user_input)
print(safe)  # price\ is\ \$10\.00\ \(USD\)

Özet

  • Regex, metin içinde karmaşık kalıplara göre arama, eşleştirme ve değiştirme yapmanın güçlü yoludur. re modülü ile kullanılır.

  • Temel fonksiyonlar: search() ilk eşleşme, findall() tüm eşleşmeler, sub() bul-değiştir, split() böl, finditer() lazy eşleşme.

  • Karakter sınıfları (\d, \w, \s, \b) ve quantifier'lar (*, +, ?, {n,m}) pattern'lerin yapı taşlarıdır. Greedy vs lazy farkını unutma.

  • Gruplar () ile yakalama, (?:...) non-capturing, (?P<name>...) named group olarak kullanılır.

  • `re.compile()` ile tekrar kullanılacak pattern'leri önceden derle. Flag'ler (re.I, re.M, re.S, re.X) davranışı özelleştirir.

  • Regex güçlü ama okuması zor olabilir. re.VERBOSE ile yorum ekle, karmaşık pattern'leri parçala ve her zaman raw string (r"") kullan.