This tool runs entirely in your browser. Nothing you paste is uploaded.
How you can check →Python regex tester — re module rules, Unicode-by-default, 3.11+ possessive quantifiers
Ships in: Python 3.11+
Want to test your own pattern under Python 3.11+ (re)? Open the regex tester with this flavor already selected.
Open the regex tester — Python 3.11+ (re) →Python's re module is one of the more forgiving mainstream engines to reason about, with one big exception most people learn the hard way: \d, \w and \s match the full Unicode categories by default on str patterns, not just ASCII. re.ASCII (or the inline (?a) flag) reverts them to the [0-9], [A-Za-z0-9_] and ASCII-whitespace ranges most people expect from experience with JavaScript or Go. If you've ever had a "digits-only" Python validator accept Eastern Arabic-Indic numerals or full-width digits nobody typed on a US keyboard, this is why — and it's the single most common reason a pattern that passed code review in Python fails the exact same input differently in Java or Go.
Lookbehind is fixed-width only — (?<=a+) raises re.error at compile time, the same restriction PCRE2 enforces, and unlike JavaScript, .NET and Java, all three of which accept genuinely variable-width lookbehind. This is the rule that breaks most often when a pattern gets copied from a JavaScript regex tester into a Python script: it isn't slower in Python, it simply refuses to compile, with a message that names the construct rather than the input.
Possessive quantifiers (a++) and atomic groups ((?>...)) are real Python syntax — but only from Python 3.11 onward. Code that has to run on 3.10 or earlier cannot use either, and there is no graceful degradation: it's a SyntaxError-equivalent PatternError on the older interpreter, not a silent fallback to ordinary backtracking. If you're hardening a pattern against catastrophic backtracking for a library that still supports older Python, the atomic-group fix this tool's Analyse tab suggests may not be available to you at all, and a restructured pattern is the safer target.
Named groups use (?P<name>...) rather than the (?<name>...) form JavaScript, Java, .NET and PCRE2 all also accept — Python's re module rejects the angle-bracket-only spelling outright with "unknown extension", even though it otherwise recognizes named-group semantics perfectly well. The matching backreference syntax is (?P=name), and the replacement-template equivalent is \g<name> rather than $<name> or ${name} — three separate substitutions to make by hand if you're porting a pattern and its replacement together from JavaScript or .NET.
$ without the multiline flag has the same quiet convenience (and quiet trap) as PCRE2, .NET and Java: it matches the true end of the string, or just before one single trailing newline. ^\d+$ against "42\n" matches in Python — and does not match in JavaScript or Go, which is the most common single cause of "why does this validation regex behave differently in my Python backend and my JavaScript frontend" questions anywhere online.
Global iteration in Python is finditer / re.sub, not a stateful lastIndex like JavaScript's g flag — and empty-match handling around zero-width matches changed in Python 3.7, which is worth knowing if you're debugging match counts against an older reference. This tool's engine implements the code-point advance rule Python itself uses, so the count shown here for a* against "bb" (three matches, not two) is the count re.findall would actually return.
Free-spacing mode, re.VERBOSE (or the inline (?x) flag), is Python's answer to the same readability problem PCRE2's x modifier and Java's COMMENTS flag both solve: unescaped whitespace inside the pattern is ignored and # starts a comment running to end of line, which makes a pattern like a date extractor readable as a small paragraph with each field annotated rather than one dense line. The one thing to remember is that re.VERBOSE changes how whitespace inside the pattern is parsed, so a literal space that needs to survive has to be written as \ or inside a character class — an easy detail to lose the first time a working pattern is reformatted into verbose style and quietly stops matching spaces it used to.
Because Python's re module compiles patterns once and reuses the compiled object, it's also worth testing a pattern here exactly as it will be written in code — re.compile(pattern, flags) — rather than as a bare string, since the flags argument is where re.ASCII, re.VERBOSE and re.MULTILINE actually get attached, and a pattern that behaves one way when pasted bare into this tool's pattern bar needs those same flags reproduced in the compile call for the behavior to match in the real script.
Python 3.11+ (re) quirks, at a glance
The same facts this tool's engine implements and tests against — not a separate, unverified summary.
- \d, \w and \s match the full Unicode categories by default on str patterns — re.ASCII reverts them to [0-9], [A-Za-z0-9_] and ASCII whitespace.
- Lookbehind must be fixed-width: (?<=a+) is a re.error, unlike JavaScript, .NET and Java where it compiles.
- Possessive quantifiers (a++) and atomic groups ((?>...)) only exist from Python 3.11 — code targeting 3.10 or earlier cannot use them.
A worked example: Python (re)
Extracting a date like 2026-08-22 — (?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2}).
re.compile(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})")
\d and \w are Unicode-aware by default on str patterns in Python 3 — pass re.ASCII to restrict them to ASCII, the way most other flavors already behave.
Frequently asked questions
- Does \d match non-ASCII digits in Python?
- Yes, by default — Python's re module makes \d, \w and \s Unicode-aware on str patterns. Use re.ASCII (or the inline (?a) flag) to restrict them back to the ASCII ranges most other flavors default to.
- Why does (?<=a+)b fail to compile in Python?
- Python's re module requires lookbehind to be fixed-width — any variable-length quantifier inside (?<=...) raises an error at compile time. This is the same rule PCRE2 enforces; JavaScript, .NET and Java all permit variable-width lookbehind instead.
- Can I use possessive quantifiers in Python?
- Only from Python 3.11 onward. a++ and atomic groups ((?>...)) both raise a pattern error on 3.10 and earlier — there's no automatic fallback to ordinary backtracking.
- Why do I get "unknown extension" for (?<name>...) in Python?
- Python's re module only accepts the (?P<name>...) spelling for named groups; the angle-bracket-only form that JavaScript, Java, .NET and PCRE2 all also support is rejected outright, even though named-group semantics are otherwise identical.
Other flavors
ECMAScript RegExp, exactly as your browser or Node runs it
the engine behind PHP's preg_* and most Apache/nginx rewrite rules
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