PHP PCRE
PHP’s regex API is PCRE: preg_match, preg_match_all, preg_replace, preg_replace_callback, preg_split. Patterns are strings with delimiters (e.g. /.../, #...#) and flags.
preg_* recipes that ship in real code
EXAMPLE
<?php
// 1) Match — preg_match returns 0 or 1; captures land in $m
$line = 'order id=12345 status=paid total=99.95';
if (preg_match('/id=(\d+)\s+status=(\w+)\s+total=([\d.]+)/', $line, $m)) {
[$_, $id, $status, $total] = $m;
// $id = '12345', $status = 'paid', $total = '99.95'
}
// 2) Match all — preg_match_all
$html = '<a href="/x">x</a><a href="https://y.com">y</a>';
preg_match_all('/href="([^"]+)"/', $html, $m);
// $m[1] = ['/x', 'https://y.com']
// 3) Replace
$slug = preg_replace('/[^a-z0-9]+/i', '-', strtolower('Hello, World!'));
// 'hello-world-'
$slug = trim($slug, '-');
// 4) Replace with callback — for context-dependent transforms
$text = preg_replace_callback(
'/\b(\d{4})-(\d{2})-(\d{2})\b/',
fn($m) => DateTime::createFromFormat('Y-m-d', $m[0])->format('j M Y'),
'Booking on 2026-06-07 confirmed.'
);
// 'Booking on 7 Jun 2026 confirmed.'
// 5) Split
$parts = preg_split('/\s*,\s*/', 'a, b,c , d');
// ['a', 'b', 'c', 'd']
// 6) Named groups — (?<name>...)
if (preg_match('/^(?<user>[^@]+)@(?<host>.+)$/', $email, $m)) {
$user = $m['user'];
$host = $m['host'];
}
// 7) Multiline + case-insensitive + extended whitespace
preg_match('/^ERROR:.*$/im', $log, $m);
// 8) Useful patterns
preg_match('/^[\w.+-]+@[\w-]+\.[\w.-]+$/', $input); // crude email
preg_match('/^https?:\/\/[^\s"<>]+$/', $url); // URL-ish
preg_match('/^[+]?[0-9 ()-]{7,20}$/', $phone); // loose phone
preg_match_all('/#\w+/', $tweet, $m); // hashtags
// 9) Catch a bad regex BEFORE it hits prod
if (@preg_match($pattern, '') === false) {
throw new InvalidArgumentException('bad regex: ' . preg_last_error_msg());
}
// 10) Performance pitfalls
// • Don't compile inside a tight loop — assign once, reuse
// • Catastrophic backtracking — avoid `(a+)+`, use atomic groups (?>...) or possessive quantifiers (a++)
// • For literal-string search, use strpos / str_contains — they're O(n) instead of regex's overhead
// 11) Replace multiple patterns in one call — arrays
$clean = preg_replace(
['/\s+/', '/[^\w -]/'],
[' ', ''],
$dirty
);
Why it matters
preg_replace_callback is the most under-used PHP regex function — any replacement that depends on the capture (date reformatting, normalisation, escaping) is one line cleaner than a pre-pass and a second regex.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
if (preg_match('/(?P<area>\d{3})-(?P<num>\d{4})/', '555-867-5309', $m)) {
echo $m['area'], ' ', $m['num'];
}
Try it Yourself »
Discussion
Loading…