Laravel'de Regex: Validation, Route Pattern ve Günlük Kullanım
Regex (Regular Expressions) cogu gelistiricinin korkulu ruyasi ama bir kez ogrendiginde vazgecemedigin bir arac. Laravel'de validation'dan route tanimlamaya, string manipulasyondan veri temizlemeye kadar pek cok yerde regex kullaniyorum. Bu makalede regex temellerini hizlica ozetleyip, Laravel'de pratik kullanim orneklerini paylasiyorum.
Regex Temelleri: Hizli Referans
Detayli bir regex kursu vermek niyetinde degilim ama temel pattern syntax'ini hatirlayalim:
. Herhangi bir karakter
\d Rakam [0-9]
\w Harf, rakam veya _ [a-zA-Z0-9_]
\s Bosluk karakteri (space, tab, newline)
^ Satir basi
$ Satir sonu
+ 1 veya daha fazla
* 0 veya daha fazla
? 0 veya 1
{n} Tam n kez
{n,m} n ile m arasi
[abc] a, b veya c
[^abc] a, b, c disinda
(...) Grup yakalama
(?:...) Grup yakalama yapmadan gruplama
| Veya (alternation)
Bu temel bilgiyle Laravel'deki kullanim alanlarini inceleyelim.
Laravel Validation'da Regex
Laravel'in regex validation rule'u en sik kullandigim araclardan biri. Form input'larini belirli bir pattern'e uygun olup olmadigini kontrol etmek icin ideal.
Temel Kullanim
$request->validate([
'username' => ['required', 'regex:/^[a-zA-Z0-9_-]+$/'],
'phone' => ['required', 'regex:/^0[0-9]{10}$/'],
]);
Onemli bir nokta: regex rule'u | (pipe) ile ayirirken sorun yasayabilirsiniz cunku regex icinde de | kullanilabilir. Bu yuzden validation rule'larini her zaman array syntax ile yaziyorum.
// YANLIS - pipe ile ayirinca regex'teki | karisir
'field' => 'required|regex:/^(foo|bar)$/'
// DOGRU - array syntax kullan
'field' => ['required', 'regex:/^(foo|bar)$/']
TC Kimlik No Dogrulama
Turkiye'ye ozel bir ornek. TC kimlik numarasi 11 haneli, ilk hane 0 olamaz:
$request->validate([
'tc_kimlik' => [
'required',
'regex:/^[1-9][0-9]{10}$/',
],
]);
Ama sadece regex yetmez. TC kimlik numarasinin algoritmik dogrulamasi da var. Bunu custom rule ile birlestiriyorum:
// app/Rules/TcKimlik.php
class TcKimlik implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (! preg_match('/^[1-9][0-9]{10}$/', $value)) {
$fail('Gecerli bir TC Kimlik numarasi giriniz.');
return;
}
$digits = str_split($value);
$sum_odd = $digits[0] + $digits[2] + $digits[4] + $digits[6] + $digits[8];
$sum_even = $digits[1] + $digits[3] + $digits[5] + $digits[7];
$d10 = ($sum_odd * 7 - $sum_even) % 10;
$d11 = array_sum(array_slice($digits, 0, 10)) % 10;
if ($digits[9] != $d10 || $digits[10] != $d11) {
$fail('TC Kimlik numarasi algoritmik olarak gecersiz.');
}
}
}
Telefon Numarasi (Turkiye)
Turkiye telefon numaralari icin esneklik saglayan bir pattern:
$request->validate([
// 05XX XXX XX XX veya +905XXXXXXXXX veya 5XXXXXXXXX
'phone' => ['required', 'regex:/^(\+?90|0)?5[0-9]{9}$/'],
]);
IBAN Dogrulama
Turkiye IBAN'i TR ile baslar ve toplam 26 karakter:
$request->validate([
'iban' => ['required', 'regex:/^TR[0-9]{24}$/'],
]);
Plaka Dogrulama
Turkiye plaka sistemi biraz karmasik ama temel pattern'i yakalayabiliriz:
$request->validate([
// 06ABC123 veya 34AB1234 formatinda
'plaka' => [
'required',
'regex:/^(0[1-9]|[1-7][0-9]|8[01])[A-Z]{1,3}[0-9]{1,4}$/',
],
]);
Route Parametrelerinde Where Constraint
Laravel route tanimlarinda where metodu ile regex constraint eklemek cok faydali. Ozellikle slug, id gibi parametreleri kisitlamak icin kullaniyorum.
// Sadece rakam kabul et
Route::get('/users/{id}', [UserController::class, 'show'])
->where('id', '[0-9]+');
// Sadece slug formati (kucuk harf, rakam, tire)
Route::get('/blog/{slug}', [BlogController::class, 'show'])
->where('slug', '[a-z0-9-]+');
// Birden fazla parametre
Route::get('/{category}/{slug}', [PostController::class, 'show'])
->where([
'category' => '[a-z]+',
'slug' => '[a-z0-9-]+',
]);
Laravel 9+ ile gelen helper metotlar daha okunakli:
Route::get('/users/{id}', [UserController::class, 'show'])
->whereNumber('id');
Route::get('/blog/{slug}', [BlogController::class, 'show'])
->whereAlphaNumeric('slug');
Route::get('/locale/{locale}', [LocaleController::class, 'set'])
->whereIn('locale', ['tr', 'en', 'de']);
Global pattern tanimlamak icin RouteServiceProvider veya AppServiceProvider boot metodunu kullaniyorum:
// AppServiceProvider boot()
Route::pattern('id', '[0-9]+');
Route::pattern('slug', '[a-z0-9-]+');
Boylece tum route'larda {id} otomatik olarak sadece rakamlari kabul eder.
Str::of() ile Regex Islemleri
Laravel'in Str facade'i ve fluent string API'si regex islemlerini cok kolaylastiriyor.
match ve matchAll
use Illuminate\Support\Str;
// Tek eslesme
$result = Str::of('Fiyat: 149.90 TL')->match('/[0-9]+\.?[0-9]*/');
// "149.90"
// Tum eslesmeler
$prices = Str::of('Urun A: 49.90 TL, Urun B: 99.50 TL')
->matchAll('/[0-9]+\.[0-9]+/');
// ["49.90", "99.50"]
replaceMatches
// Telefon numarasini maskele
$masked = Str::of('0532 123 45 67')
->replaceMatches('/(\d{4})\s(\d{3})\s(\d{2})\s(\d{2})/', '$1 *** ** $4');
// "0532 *** ** 67"
// HTML tag'lerini temizle
$clean = Str::of('<p>Merhaba <b>Dunya</b></p>')
->replaceMatches('/<[^>]+>/', '');
// "Merhaba Dunya"
test (Boolean Kontrol)
$isEmail = Str::of('[email protected]')->test('/^[\w.-]+@[\w.-]+\.\w+$/');
// true
$hasNumber = Str::of('abc123')->test('/\d/');
// true
preg_match ve preg_replace ile Ileri Kullanim
Bazen Laravel helper'lari yetmez, dogrudan PHP regex fonksiyonlarina ihtiyac duyarim.
// Log dosyasindan hata satirlarini parse et
$log = '[2026-02-25 14:30:00] production.ERROR: Connection refused';
if (preg_match('/\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] \w+\.(\w+): (.+)/', $log, $matches)) {
$timestamp = $matches[1]; // 2026-02-25 14:30:00
$level = $matches[2]; // ERROR
$message = $matches[3]; // Connection refused
}
Named capture groups ile daha okunakli:
$pattern = '/\[(?P<date>\d{4}-\d{2}-\d{2})\s(?P<time>\d{2}:\d{2}:\d{2})\]\s\w+\.(?P<level>\w+):\s(?P<message>.+)/';
if (preg_match($pattern, $log, $matches)) {
echo $matches['level']; // ERROR
echo $matches['message']; // Connection refused
}
Sik Yapilan Hatalar
1. Delimiter unutmak veya karistirmak:
// YANLIS - delimiter yok
'regex:/^[a-z]+$'
// DOGRU
'regex:/^[a-z]+$/'
2. ^ ve $ kullanmamak:
// Tehlikeli - "abc123!@#" da eslesir cunku icinde rakam var
'regex:/[0-9]+/'
// Guvenli - sadece rakamlardan olusmali
'regex:/^[0-9]+$/'
3. Greedy vs Lazy quantifier:
$html = '<div>merhaba</div><div>dunya</div>';
// Greedy - her seyi yakalar: <div>merhaba</div><div>dunya</div>
preg_match('/<div>(.+)<\/div>/', $html, $m);
// Lazy - sadece ilkini yakalar: <div>merhaba</div>
preg_match('/<div>(.+?)<\/div>/', $html, $m);
4. Turkce karakter sorunu:
// Turkce karakterleri icermiyor
'regex:/^[a-zA-Z]+$/'
// Turkce karakterleri iceriyor - u flag ile Unicode destegi
'regex:/^[\p{L}]+$/u'
// Veya manuel olarak
'regex:/^[a-zA-ZcCgGiIoOsSuU]+$/'
Pratik Bir Ornek: Icerik Temizleme Servisi
Projelerimde kullanici girdilerini temizlemek icin bir servis sinifi kullaniyorum:
class ContentSanitizer
{
public function cleanPhone(string $phone): string
{
// Tum bosluk ve ozel karakterleri kaldir
$clean = preg_replace('/[^0-9+]/', '', $phone);
// Basta 0 varsa +90 ile degistir
return preg_replace('/^0/', '+90', $clean);
}
public function extractEmails(string $text): array
{
preg_match_all('/[\w.-]+@[\w.-]+\.\w{2,}/', $text, $matches);
return array_unique($matches[0]);
}
public function slugify(string $text): string
{
$text = mb_strtolower($text, 'UTF-8');
$text = str_replace(
['c', 'g', 'i', 'o', 's', 'u'],
['c', 'g', 'i', 'o', 's', 'u'],
$text
);
$text = preg_replace('/[^a-z0-9]+/', '-', $text);
return trim($text, '-');
}
}
Sonuc
Regex ilk bakista korkutucu gorunse de Laravel'de cok guclu bir arac. Validation'da input kontrolu, route'larda parametre kisitlamasi, string islemlerinde veri parse etme -- hepsinde regex kullaniyorum. Onemli olan dogru yerde dogru miktarda kullanmak. Her seyi regex ile cozmeye calismak yerine, basit string islemleri icin Str helper'larini, karmasik dogrulama icin custom rule'lari tercih edin. Ama regex gerektiginde de cekinmeyin; bir kez alisinca gercekten vazgecilmez oluyor.