Regex in PHP

PHP uses PCRE (Perl Compatible Regular Expressions) through the preg_* function family. PCRE is one of the most feature-rich regex engines available, supporting lookaround, backreferences, recursive patterns, and conditional subpatterns.

Code Examples

Basic matching with preg_match()

<?php
// preg_match returns 1 on match, 0 on no match
$text = "Order #12345 placed";
if (preg_match('/#(\d+)/', $text, $matches)) {
    echo $matches[0]; // "#12345"  (full match)
    echo $matches[1]; // "12345"   (group 1)
}

// Simple boolean check
$isEmail = preg_match('/^[\w.+-]+@[\w-]+\.[\w.]+$/i', $input);

preg_match() finds the first match. The third argument ($matches) is filled with the match and capture groups. Returns 1 on success, 0 on failure, or false on error.

Find all matches

<?php
$text = "Prices: $12.99, $5.50, $120.00";
preg_match_all('/\$(\d+\.\d{2})/', $text, $matches);

print_r($matches[0]); // ["$12.99", "$5.50", "$120.00"]
print_r($matches[1]); // ["12.99", "5.50", "120.00"]

// With PREG_SET_ORDER: groups each match together
preg_match_all('/\$(\d+)\.(\d{2})/', $text, $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
    echo "$m[0] -> dollars: $m[1], cents: $m[2]\n";
}

preg_match_all() finds every match. By default, $matches[0] contains all full matches, $matches[1] all group-1 captures, etc. Use PREG_SET_ORDER to group by match instead.

Named capture groups

<?php
$date = "2026-03-08";
$pattern = '/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/';

if (preg_match($pattern, $date, $m)) {
    echo $m['year'];  // "2026"
    echo $m['month']; // "03"
    echo $m['day'];   // "08"
}

PHP supports both (?P<name>...) and (?<name>...) syntax for named groups. Access them by name in the $matches array.

Search and replace

<?php
// Simple replacement
$result = preg_replace('/\bfoo\b/', 'bar', 'foo is not foobar');
echo $result; // "bar is not foobar"

// Replacement with backreferences
$swapped = preg_replace('/(\w+)\s(\w+)/', '$2, $1', 'John Smith');
echo $swapped; // "Smith, John"

// Replace with a callback
$upper = preg_replace_callback('/\b[a-z]/', function($m) {
    return strtoupper($m[0]);
}, 'hello world');
echo $upper; // "Hello World"

preg_replace() handles static replacements with $1, $2 backreferences. preg_replace_callback() lets you use a function for dynamic replacements.

Split with preg_split()

<?php
$csv = "one, two ,three,  four";
$parts = preg_split('/\s*,\s*/', $csv);
print_r($parts); // ["one", "two", "three", "four"]

// PREG_SPLIT_NO_EMPTY removes empty strings
$tokens = preg_split('/[\s,]+/', "  a,,b , c  ", -1, PREG_SPLIT_NO_EMPTY);
print_r($tokens); // ["a", "b", "c"]

preg_split() splits a string by a regex pattern. Use PREG_SPLIT_NO_EMPTY to filter out empty segments. Pass -1 as the limit for unlimited splits.

Recursive patterns

<?php
// Match balanced parentheses (PCRE-specific feature)
$pattern = '/\((?:[^()]+|(?R))*\)/';
$text = "func(a, inner(b, c), d)";

preg_match($pattern, $text, $m);
echo $m[0]; // "(a, inner(b, c), d)"

PHP's PCRE engine supports recursive patterns with (?R) or (?n). This is a powerful feature not available in most other regex engines — useful for matching nested structures like balanced brackets.

Note

PHP regex patterns must be enclosed in delimiters — typically forward slashes (/pattern/flags), but any non-alphanumeric character works (e.g., #pattern#, ~pattern~). Common modifiers: i (case-insensitive), m (multiline), s (dotall), x (extended/verbose), u (UTF-8 Unicode). Always check preg_last_error() after preg_* calls in production code to catch PCRE errors.

Regex in Other Languages

Frequently Asked Questions

What delimiters should I use for PHP regex?

Forward slashes (/) are most common: '/pattern/i'. If your pattern contains many slashes, use an alternative delimiter to avoid excessive escaping: '#http://.*#i' or '~path/to/file~'. Any non-alphanumeric, non-backslash, non-whitespace character works as a delimiter.

What is the difference between PCRE and POSIX regex in PHP?

PHP's ereg_* functions (POSIX) were removed in PHP 7.0. The preg_* functions (PCRE) are the only regex option in modern PHP. PCRE is faster and more feature-rich than POSIX, supporting lookaround, non-greedy quantifiers, named groups, and recursive patterns.

How do I handle Unicode in PHP regex?

Add the u modifier to enable UTF-8 mode: '/\w+/u'. Without it, \w, \d, and . only work with ASCII characters. With the u flag, \w matches Unicode letters and \p{L} (Unicode letter property) becomes available. Make sure your input string is valid UTF-8.

Why does preg_match return false instead of 0?

preg_match() returns false (not 0) on error — for example, if the pattern is invalid or PCRE hits an internal limit. Always use === to compare: if (preg_match(...) === false) for error checking, or if (preg_match(...)) for a simple truthy check. Call preg_last_error() to get the specific error code.

Want to test a PHP regex pattern? Our regex tester runs JavaScript's native RegExp engine in your browser — paste your pattern and see matches in real time.

← Open the Regex Tester