This tool runs entirely in your browser. Nothing you paste is uploaded.
How you can check →PCRE2 regex tester — the engine behind PHP's preg_* and most Apache/nginx rewrite rules
Ships in: PHP (preg_*), R, Apache/nginx rewrite rules, many C/C++ tools
Want to test your own pattern under PCRE2? Open the regex tester with this flavor already selected.
Open the regex tester — PCRE2 →PCRE2 is not a language — it's the C library that PHP's preg_match, preg_replace and the rest of the preg_* family are a thin wrapper over, and it is also what most Apache mod_rewrite rules, nginx rewrite/location directives, and a long list of C and C++ tools compile against directly. If your pattern's real destination is a .htaccess file or a preg_match call, this is the flavor that actually matters, not a JavaScript approximation of it.
The rule most worth knowing before you paste a pattern in from another engine: lookbehind must be fixed-width per alternative. (?<=abc) compiles fine because every branch of it is exactly three characters wide. (?<=a+) does not — a variable-length quantifier inside lookbehind is a compile-time error here, the same restriction Python enforces. PCRE2 is slightly more permissive than Python in one specific way: different alternatives inside one lookbehind are allowed to have different fixed widths from each other, as long as each individual alternative is itself fixed. .NET and Java both allow genuinely unbounded-width lookbehind, which is the real trap when porting a pattern from either of those toward PHP.
\d, \w and \s stay ASCII-only by default, exactly like JavaScript, unless the u modifier — PCRE2_UCP internally, PHP's u modifier at the preg_* call site — is explicitly set. This matters more here than almost anywhere else on this page because PHP's own preg_* functions do not turn PCRE2_UCP on by default, so a pattern written and tested assuming Unicode-aware \d will quietly under-match the moment it meets a non-ASCII digit in production, with no error and no warning.
Named groups accept two spellings here — (?<name>...) and (?P<name>...) both compile, which is friendlier than most flavors that only take one. Named backreferences follow PCRE2's own \g{name} syntax rather than JavaScript's \k<name> or Python's (?P=name), so a pattern copied verbatim between PHP and either of those needs that one substitution even when everything else translates unchanged.
Duplicate group names — the same name used for two different capturing groups in one pattern — are rejected as a compile error unless the pattern explicitly opts in with the (?J) modifier. This is the opposite default from .NET, which allows duplicate names unconditionally; a pattern that relies on .NET's default behavior will need that modifier added before it compiles under PCRE2.
PCRE2 also supports possessive quantifiers (a++) and atomic groups ((?>...)) natively, both of which are the standard fix this tool's Analyse tab suggests for a pattern flagged as exponential — useful to know if you're hardening a PHP validation regex against catastrophic backtracking rather than just testing that it matches the happy path.
Free-spacing mode — PCRE2_EXTENDED, PHP's x modifier — is worth reaching for the moment a pattern grows past a handful of tokens, because it's one of the few places PCRE2 is strictly more readable than the equivalent JavaScript. With x set, unescaped whitespace inside the pattern is ignored entirely and # starts a comment that runs to end of line, so a date pattern can be laid out one field per line with an explanation beside each, and still compile to exactly the same automaton as the dense single-line version. JavaScript has no equivalent flag at all — free-spacing is a PCRE2/Python/Java feature specifically, not a universal one, so a heavily commented pattern built this way in PHP has to be collapsed back to a single line before it will mean anything to `new RegExp(...)`.
$ without the multiline modifier carries the same convenience — and the same trap for anyone assuming JavaScript's stricter rule — as Python, Java and .NET: it matches the true end of the subject, or just before one single trailing newline. PCRE2_DOLLAR_ENDONLY (PHP's D modifier) turns that convenience off and reverts $ to end-of-subject-only, which is the specific knob to reach for if a validation pattern needs to reject trailing-newline input rather than quietly accept it, without switching flavors entirely to get JavaScript's stricter default.
Because PCRE2 sits underneath so much infrastructure that isn't a general-purpose programming language — Apache's mod_rewrite, nginx's rewrite and location blocks, R's stringr package built on it — it's worth testing a rewrite-rule pattern here even when nothing about your actual work is PHP. The engine, and every one of the divergences above, is identical regardless of which piece of infrastructure is calling into it.
PCRE2 quirks, at a glance
The same facts this tool's engine implements and tests against — not a separate, unverified summary.
- \d, \w and \s stay ASCII-only unless the u modifier (PCRE2_UCP) is set — PHP's preg_* does not set it by default.
- Lookbehind must be fixed-width per alternative: (?<=abc) is fine, (?<=a+) is not — Python matches this rule too, but PCRE2 allows differing fixed widths across | branches within one lookbehind.
- Duplicate group names are only allowed with the (?J) modifier; without it they are a compile error.
A worked example: PHP (preg_match)
Extracting a date like 2026-08-22 — ^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$.
preg_match('/^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/', $subject)
Any literal / inside the pattern must itself be escaped as \/, since PHP uses the delimiter character to bound the pattern. PHP's PCRE also does not enable Unicode-aware \d by default — pass the u modifier for that.
Frequently asked questions
- Is this the same engine PHP's preg_match uses?
- Yes — PHP's preg_* functions are a wrapper around PCRE2, and this flavor implements PCRE2's own rules: fixed-width lookbehind, ASCII-only \d/\w/\s unless the u modifier is set, and \g{name} for named backreferences.
- Why did my .NET lookbehind pattern fail to compile here?
- PCRE2 requires lookbehind to be fixed-width per alternative — a variable-length quantifier like a+ inside (?<=...) is a compile error. .NET allows genuinely unbounded-width lookbehind, so a pattern relying on that needs restructuring, not just a syntax tweak, before it will compile under PCRE2.
- Does PHP's preg_match match Unicode digits with \d?
- Not by default. PCRE2_UCP (PHP's u modifier) has to be set explicitly, and PHP's preg_* functions don't set it for you — an unmarked \d stays ASCII-only.
- Can I have two capturing groups with the same name?
- Only with the (?J) modifier — without it, a duplicate group name is a compile-time error, unlike .NET, which permits duplicate names unconditionally.
Other flavors
ECMAScript RegExp, exactly as your browser or Node runs it
re module rules, Unicode-by-default, 3.11+ possessive quantifiers
java.util.regex rules for Java, Kotlin, Scala and Android
System.Text.RegularExpressions rules, including the group-numbering quirk
RE2 rules, including why lookaround and backreferences don't compile
POSIX ERE and leftmost-longest matching, not leftmost-first
POSIX BRE, where ( ) and { } are literal and \( \) \{ \} do the work