1. Home
  2. PHP Regex Tester

PHP Regex Tester

Test patterns with PHP's real PCRE engine, not JavaScript's. See every match and capture group highlighted, then copy the preg_* code.

PHP 8.4 · loads on first use
Matches in the text
Press Test. Results update as you type once PHP has loaded.
Groups
Capture groups appear here.
PHP code

Runs PHP 8.4 compiled to WebAssembly in your browser (about 5 MB, cached after the first load). Nothing is uploaded.

PHP regex cheat sheet

The PCRE syntax you use most, and the modifiers that go after the closing delimiter.

SyntaxMeaning
.Any character except a newline (add the s modifier to include newlines)
\d \w \sA digit, a word character [A-Za-z0-9_], whitespace
\D \W \SThe opposite of each
[abc] [^abc] [a-z]One of, none of, a range
^ $Start and end of the string (of each line with the m modifier)
\bWord boundary
* + ?0 or more, 1 or more, 0 or 1
{3} {2,} {2,5}Exactly 3, at least 2, between 2 and 5
*? +?Lazy: match as little as possible
( )Capturing group, available as $1, $2 … in replacements
(?: )Group without capturing
(?<name> )Named group, available as $matches['name']
a|ba or b
(?= ) (?! )Lookahead: followed by, not followed by
(?<= ) (?<! )Lookbehind: preceded by, not preceded by
\1Backreference to group 1
ModifierEffect
iCase-insensitive
mMultiline: ^ and $ match at line breaks
sDot matches newlines too
xExtended: whitespace and # comments in the pattern are ignored
uUTF-8: treat pattern and subject as Unicode. Use it for any non-ASCII text
UUngreedy: quantifiers are lazy by default
D$ matches only at the very end, not before a final newline

The preg functions at a glance

  • preg_match($pattern, $subject, $matches) returns 1 if the pattern matches, 0 if not, false on error. $matches[0] is the whole match, $matches[1] the first group.
  • preg_match_all() returns the number of matches and fills $matches with all of them.
  • preg_replace($pattern, $replacement, $subject) returns the new string. In the replacement, $1 or \1 inserts group 1, and ${1} separates it from following digits.
  • preg_replace_callback() calls a function for each match, for replacements that need logic.
  • preg_split() splits a string at each match, like explode() with a pattern.
  • preg_quote($text, '/') escapes user input so it can be placed inside a pattern safely.

Why test with real PHP

Most online regex testers run your pattern with JavaScript's engine. That is fine for simple patterns but gives wrong answers for PHP-specific behaviour: the x, U and D modifiers, possessive quantifiers, atomic groups, recursion, \A and \z, Unicode handling without the u modifier, and error messages for invalid patterns. This tester sends your pattern to preg_match_all() in a real PHP 8.4 build running in your browser, so the result is what your server will produce. Byte offsets returned by PCRE are converted to characters for highlighting.

Common mistakes in PHP regex

  • Missing delimiters: preg_match('\d+', …) fails with “Delimiter must not be alphanumeric or backslash”. Write '/\d+/'.
  • Double escaping in double quotes: in "/\d+/" PHP leaves \d alone, but "\n" becomes a real newline before PCRE sees it. Single-quoted patterns avoid surprises.
  • Greedy dot-star: /<b>.*<\/b>/ matches from the first <b> to the last </b>. Use .*?, or better, a real HTML parser such as DOMDocument.
  • Forgetting u: without it, character classes and lengths are byte-based and break on accented letters and emoji.
  • Validating email with regex: use filter_var($email, FILTER_VALIDATE_EMAIL) instead of a home-made pattern.

More PHP tools

Frequently asked questions

Why do PHP regular expressions need delimiters?

PHP's preg_* functions take the pattern and its modifiers as one string, so the pattern is wrapped in delimiters: /abc/i. Any non-alphanumeric character except backslash and whitespace works. Use ~ or # when the pattern contains slashes, such as URLs, so you do not have to escape them.

Is PHP regex the same as JavaScript regex?

No. PHP uses the PCRE2 library, JavaScript has its own engine. Most everyday syntax is shared, but PCRE has features JavaScript lacks or handles differently: possessive quantifiers a++, atomic groups (?>…), recursion (?R), conditionals, the x and U modifiers, and \A, \z, \Z. That is why this tester runs the real PHP engine instead of the browser's.

What is the difference between preg_match and preg_match_all?

preg_match() stops at the first match and returns 1 or 0. preg_match_all() finds every match and returns how many it found. Both fill the $matches array; for preg_match_all() the flag PREG_SET_ORDER groups it by match instead of by capture group.

Why does my pattern not match accented letters or emoji?

Without the u modifier, PCRE works on bytes, so \w does not match “é” and a single emoji counts as four characters. Add u to the end of the pattern, for example /\w+/u, whenever the text may contain non-ASCII characters.

What does “Backtrack limit exhausted” mean?

The pattern made PCRE try too many combinations, usually because of nested quantifiers like (a+)+ or .* followed by more .*. Rewrite the pattern to be more specific, use possessive quantifiers or atomic groups, or raise pcre.backtrack_limit as a last resort.