Swift 5.7 ile birlikte gelen RegexBuilder, metin isleme dunyasinda devrim yaratti. Artik kriptik regex pattern'leri yerine type-safe, okunabilir ve compose edilebilir DSL kullanabilirsiniz. Bu rehberde RegexBuilder'in tum gucunu kesfedeceegiz.
Icindekiler
- Neden RegexBuilder?
- Temel Regex Literal Kullanimi
- RegexBuilder DSL
- Capture Groups ve Tipli Yakalama
- Custom Parsing Stratejileri
- Gercek Dunya Ornekleri
- Performans Karsilastirmasi
- Best Practices
- Sonuc
1. Neden RegexBuilder?
Geleneksel regex pattern'leri okunmasi zor, hata ayiklamasi kabus gibi ve type-safety sunmaz. RegexBuilder bu sorunlarin tumunu cozer.
Karsilastirma Tablosu
Ozellik | Geleneksel Regex | RegexBuilder |
|---|---|---|
**Okunabilirlik** | Dusuk | Yuksek |
**Type Safety** | Yok | Tam |
**Compose Edilebilirlik** | Zor | Kolay |
**IDE Destegi** | Minimal | Tam autocomplete |
**Hata Mesajlari** | Kriptik | Anlasilir |
**Performans** | Iyi | Iyi (ayni engine) |
**Ogrenme Egrisi** | Dik | Yavas |
2. Temel Regex Literal Kullanimi
Swift 5.7 ile regex literal syntax eklendi:
swift
1// Regex literal — derleyici tarafindan dogrulanir2let emailRegex = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/3 4let email = "[email protected]"5if let match = email.wholeMatch(of: emailRegex) {6 print("Gecerli email: \(match.output)")7}8 9// String icinde arama10let text = "Bana [email protected] adresinden ulasin"11if let range = text.firstMatch(of: emailRegex) {12 print("Bulunan: \(text[range.range])")13}14 15// Tum eslesmeler16let multiText = "[email protected] ve [email protected] adresleri"17let matches = multiText.matches(of: emailRegex)18print("Toplam \(matches.count) email bulundu")Regex Operasyonlari
swift
1let input = "2024-03-15"2let dateRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/3 4if let match = input.wholeMatch(of: dateRegex) {5 print("Yil: \(match.year)")6 print("Ay: \(match.month)")7 print("Gun: \(match.day)")8}9 10// Replace islemi11let redacted = input.replacing(dateRegex, with: "XXXX-XX-XX")12print(redacted) // "XXXX-XX-XX"13 14// Split islemi15let csv = "elma,armut,portakal"16let items = csv.split(separator: /,\s*/)17print(items) // ["elma", "armut", "portakal"]3. RegexBuilder DSL
RegexBuilder, Swift'in result builder ozelligini kullanarak deklaratif regex olusturmayi saglar:
swift
1import RegexBuilder2 3// E-posta regex'i — RegexBuilder ile4let emailBuilder = Regex {5 OneOrMore {6 CharacterClass(7 .word,8 .anyOf("._%+-")9 )10 }11 "@"12 OneOrMore {13 CharacterClass(14 .word,15 .anyOf(".-")16 )17 }18 "."19 Repeat(2...) {20 CharacterClass(.word)21 }22}23 24// Kullanim ayni25if "[email protected]".wholeMatch(of: emailBuilder) != nil {26 print("Gecerli email!")27}Temel Builder Bileosenleri
swift
1import RegexBuilder2 3// One — tam olarak bir kez4let singleDigit = Regex {5 One(.digit)6}7 8// OneOrMore — bir veya daha fazla9let digits = Regex {10 OneOrMore(.digit)11}12 13// ZeroOrMore — sifir veya daha fazla14let optionalSpaces = Regex {15 ZeroOrMore(.whitespace)16}17 18// Repeat — belirli tekrar sayisi19let zipCode = Regex {20 Repeat(count: 5) {21 One(.digit)22 }23}24 25// Optionally — opsiyonel kisim26let phoneNumber = Regex {27 Optionally { "+90" }28 Repeat(count: 10) {29 One(.digit)30 }31}32 33// ChoiceOf — alternatifler34let protocol_ = Regex {35 ChoiceOf {36 "http"37 "https"38 "ftp"39 }40 "://"41}42 43// Lookahead ve NegativeLookahead44let passwordCheck = Regex {45 Lookahead {46 ZeroOrMore(.any)47 One(.digit)48 }49 Lookahead {50 ZeroOrMore(.any)51 One(.word.subtracting(.digit))52 }53 Repeat(8...) {54 One(.any)55 }56}4. Capture Groups ve Tipli Yakalama
RegexBuilder'in en guclu ozelliklerinden biri tipli capture group'lardir:
swift
1import RegexBuilder2 3// Tarih parse etme — tipli capture4let dateParser = Regex {5 Capture {6 Repeat(count: 4) { One(.digit) }7 } transform: { Int($0)! }8 "-"9 Capture {10 Repeat(count: 2) { One(.digit) }11 } transform: { Int($0)! }12 "-"13 Capture {14 Repeat(count: 2) { One(.digit) }15 } transform: { Int($0)! }16}17 18if let match = "2024-03-15".wholeMatch(of: dateParser) {19 let (_, year, month, day) = match.output20 // year: Int, month: Int, day: Int — otomatik tip donusumu!21 print("Yil: \(year), Ay: \(month), Gun: \(day)")22}TryCapture ile Guvenli Parse
swift
1import RegexBuilder2 3enum Priority: String, CaseIterable {4 case low, medium, high, critical5}6 7let taskParser = Regex {8 "["9 TryCapture {10 OneOrMore(.word)11 } transform: {12 Priority(rawValue: String($0))13 }14 "] "15 Capture {16 OneOrMore(.any)17 }18}19 20let task = "[high] Sunucu deploy et"21if let match = task.wholeMatch(of: taskParser) {22 let (_, priority, description) = match.output23 print("Oncelik: \(priority), Gorev: \(description)")24 // priority: Priority tipi — otomatik enum donusumu!25}Reference ile Backreference
swift
1import RegexBuilder2 3// HTML tag eslesitirme (acilis ve kapanis tag'i ayni olmali)4let tagRef = Reference(Substring.self)5 6let htmlTag = Regex {7 "<"8 Capture(as: tagRef) {9 OneOrMore(.word)10 }11 ">"12 ZeroOrMore(.reluctant) {13 One(.any)14 }15 "</"16 tagRef17 ">"18}19 20let html = "<div>Merhaba Dunya</div>"21if let match = html.wholeMatch(of: htmlTag) {22 print("Tag: \(match[tagRef])") // "div"23}5. Custom Parsing Stratejileri
CustomConsumingRegexComponent protocol'u ile kendi parser'larinizi yazabilirsiniz:
swift
1import RegexBuilder2 3struct CurrencyParser: CustomConsumingRegexComponent {4 typealias RegexOutput = (amount: Double, currency: String)5 6 func consuming(7 _ input: String,8 startingAt index: String.Index,9 in bounds: Range<String.Index>10 ) throws -> (upperBound: String.Index, output: RegexOutput)? {11 let remaining = input[index..<bounds.upperBound]12 13 // Para birimi sembolu14 let currencies = ["$": "USD", "€": "EUR", "£": "GBP", "₺": "TRY"]15 16 for (symbol, code) in currencies {17 if remaining.hasPrefix(symbol) {18 let afterSymbol = input.index(index, offsetBy: symbol.count)19 let numberStr = input[afterSymbol..<bounds.upperBound]20 .prefix(while: { $0.isNumber || $0 == "." || $0 == "," })21 22 let cleanNumber = numberStr.replacingOccurrences(of: ",", with: "")23 if let amount = Double(cleanNumber) {24 let end = input.index(afterSymbol, offsetBy: numberStr.count)25 return (end, (amount, code))26 }27 }28 }29 return nil30 }31}32 33// Kullanim34let priceRegex = Regex {35 CurrencyParser()36}37 38let text = "Fiyat: ₺1,299.99 + KDV"39if let match = text.firstMatch(of: priceRegex) {40 let (amount, currency) = match.output41 print("\(amount) \(currency)") // 1299.99 TRY42}6. Gercek Dunya Ornekleri
Log Parser
swift
1import RegexBuilder2 3struct LogEntry {4 let timestamp: String5 let level: String6 let message: String7}8 9let logParser = Regex {10 "["11 Capture { OneOrMore(.any.subtracting(.anyOf("[]"))) }12 "] "13 Capture {14 ChoiceOf { "INFO"; "WARN"; "ERROR"; "DEBUG" }15 }16 ": "17 Capture { OneOrMore(.any) }18}19 20let logs = """21[2024-03-15 10:30:45] INFO: Uygulama baslatildi22[2024-03-15 10:30:46] ERROR: Veritabani baglantisi basarisiz23[2024-03-15 10:30:47] WARN: Cache suresi doldu24"""25 26for line in logs.split(separator: "\n") {27 if let match = String(line).wholeMatch(of: logParser) {28 let (_, timestamp, level, message) = match.output29 let entry = LogEntry(30 timestamp: String(timestamp),31 level: String(level),32 message: String(message)33 )34 print("\(entry.level): \(entry.message)")35 }36}URL Parser
swift
1import RegexBuilder2 3let urlParser = Regex {4 Capture {5 ChoiceOf { "https"; "http" }6 }7 "://"8 Optionally {9 Capture { OneOrMore(.any.subtracting(.anyOf("@"))) }10 "@"11 }12 Capture { OneOrMore(.any.subtracting(.anyOf(":/"))) }13 Optionally {14 ":"15 Capture { OneOrMore(.digit) } transform: { Int($0)! }16 }17 Optionally {18 Capture { Regex { "/"; ZeroOrMore(.any) } }19 }20}21 22let url = "https://api.example.com:8080/v2/users?page=1"23if let match = url.wholeMatch(of: urlParser) {24 print("Protocol: \(match.1)")25 print("Host: \(match.3)")26}7. Performans Karsilastirmasi
Senaryo | NSRegularExpression | Regex Literal | RegexBuilder |
|---|---|---|---|
**Basit eslesme** | 1.0x | 1.2x | 1.2x |
**Karmasik pattern** | 1.0x | 1.1x | 1.3x |
**Cok sayida eslesme** | 1.0x | 0.9x | 1.0x |
**Compile time** | Runtime | Compile time | Compile time |
**Type safety** | Yok | Kismen | Tam |
Not: RegexBuilder ve Regex literal ayni engine'i kullanir. Performans farki ihmal edilebilir duzeydedir.
8. Best Practices
- Basit pattern'ler icin regex literal kullanin — tek satirlik eslesmelerde RegexBuilder gereksiz karmasiklik ekler
- Karmasik parsing icin RegexBuilder tercih edin — okunabilirlik ve bakim kolayligi saglar
- TryCapture ile guvenli donusum yapin — force unwrap yerine optional donusum
- CustomConsumingRegexComponent ile domain-specific parser yazin
- Regex'i bir kez olusturup yeniden kullanin — her cagirisda yeniden derleme maliyeti
ALTIN İPUCU
Bu yazının en değerli bilgisi
Bu ipucu, yazının en önemli çıkarımını içeriyor.
Easter Egg
Gizli bir bilgi buldun!
Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?
Okuyucu Ödülü
Tebrikler! Bu yaziyi sonuna kadar okudugun icin sana ozel bir hediyem var:
10. Sonuc
Swift RegexBuilder, metin isleme icin modern, type-safe ve okunabilir bir cozum sunar. Geleneksel regex'in gucunu Swift'in tip sisteminin guvenligi ile birlestirerek daha saglam kod yazmanizi saglar. Ozellikle karmasik parsing senaryolarinda RegexBuilder vazgecilmez bir arac haline gelecektir.
Sonuc ve Oneriler
RegexBuilder, Swift ekosisteminde metin isleme islemlerini koklunden degistiren bir aractir. Geleneksel regex pattern'lerinin okunaksizligi ve hata ayiklama zorlugu artik geride kaldi. Type-safe capture group'lar sayesinde derleme zamaninda hatalari yakalayabilir, CustomConsumingRegexComponent ile domain-specific parser'lar olusturabilirsiniz.
Projelerinizde RegexBuilder'a gecis yaparken asama asama ilerleyin: once basit string matching islemlerini donusturun, ardindan karmasik parsing senaryolarini ele alin. Her parser'i ayri bir struct olarak tanimlayip unit test yazmak, uzun vadede bakim maliyetini onemli olcude dusurur. Regex literal ve RegexBuilder'i birlikte kullanarak her senaryo icin en uygun araci secin.
Son olarak, performans acsindan RegexBuilder ve regex literal ayni engine'i kullandigi icin ikisi arasinda anlamli bir fark yoktur. Asil kazanim okunabilirlik, test edilebilirlik ve tip guvenligidir. Bu uc ozellik, buyuk ekiplerde ve uzun omurlu projelerde kritik oneme sahiptir.

