About the Python Regex Tester
This tester is built for people writing Python regex, patterns meant for the `re` module, `re.match`, `re.search`, `re.findall` or `re.sub`. You type a pattern and sample text, set flags, and see live match highlighting, a match count and every capture group, the same interactive workflow as testing directly in a Python REPL but without leaving the browser.
One thing worth being upfront about: the matching engine behind this page is JavaScript's native RegExp, the same engine every tool on this site uses, not CPython's actual `re`/`sre` engine. For the large majority of everyday patterns, character classes, quantifiers, groups, alternation, anchors, the two engines behave identically, so this is still a fast, accurate way to iterate on a pattern. But Python's `re` module has its own syntax and modes that JavaScript does not share, and this page exists specifically to call those differences out rather than let you discover them the hard way when a pattern that worked here fails, or vice versa, inside actual Python code.
Use it to prototype the shape of a pattern quickly, then read the differences section below before you paste anything Python-specific, like named groups or verbose mode, into your Python source.
Everything runs client-side in your browser. Nothing you type, pattern or sample text, is sent to a server.
How to use it
- Enter your pattern using standard regex syntax (character classes, quantifiers, groups, anchors) in the pattern field.
- If your pattern uses Python-only syntax like (?P<name>...) or \A / \Z, translate it first using the syntax table below; this tester's engine does not accept Python-only forms directly.
- Set flags: i for case-insensitive (Python's re.IGNORECASE), m for multiline (re.MULTILINE), s for dot-matches-newline (re.DOTALL).
- Paste the sample text you want to test against, the same text you would run re.findall or re.search on in Python.
- Review the live match count, highlighted matches and capture groups.
- Once the pattern behaves correctly here, translate any Python-specific syntax back in (named groups, \A/\Z, verbose mode) before dropping it into your Python source.
- For a final check on Python-only constructs (verbose mode, possessive quantifiers, atomic groups), still run the pattern once in an actual Python shell, since this tester cannot execute those directly.
Examples
- Pattern (?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2}) is valid Python but must be entered here as (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}) using angle brackets instead of ?P, since that is the JavaScript named-group syntax this engine understands.
- Python's r"\d+\.\d+" (a raw string containing \d+\.\d+) is entered here simply as \d+\.\d+, the raw-string prefix is a Python source-code concern and is not part of the pattern itself.
- A pattern meant to use Python's \A and \Z (absolute start/end of string, unaffected by MULTILINE) is tested here using ^ and $ without the m flag, which gives the equivalent behavior in JavaScript.
- re.findall(r"(\w+)@(\w+)", text) in Python corresponds to entering (\w+)@(\w+) here with the g flag set, which is what makes the tester return every match instead of only the first.
- A pattern written with Python's re.VERBOSE in mind, spread across lines with # comments, has no direct equivalent flag here; test the pattern in its compact single-line form instead, since JavaScript has no verbose mode.
Python re vs JavaScript RegExp: syntax differences
Python's `re` module and JavaScript's RegExp both implement roughly the same class of backtracking regex, but their syntax for some common features diverges enough to trip people up when moving a pattern between the two, or when testing a Python pattern in a tool (like this one) that runs on the JavaScript engine.
- Named groups: Python uses (?P<name>...), JavaScript uses (?<name>...); a backreference to a named group is (?P=name) in Python versus \k<name> in JavaScript
- String anchors: Python has \A and \Z for the absolute start and end of the string regardless of MULTILINE; JavaScript has no \A/\Z, use ^ and $ without the m flag for the same effect
- Verbose mode: Python's re.VERBOSE flag (or inline (?x)) lets you spread a pattern across lines with whitespace and # comments ignored; JavaScript has no equivalent flag or inline modifier
- Dot-matches-newline: Python's re.DOTALL flag (or inline (?s)) makes . Match newlines; JavaScript's equivalent is the s (dotAll) flag
- Possessive quantifiers and atomic groups: Python 3.11 added *+, ++, ?+ and (?>...); JavaScript has no native possessive quantifier or atomic group syntax, so a pattern relying on them cannot be tested as-is here
- Case-insensitive matching and word boundaries (\b, \d, \w, \s) behave the same in both, so most everyday patterns need no translation at all
How to translate a Python pattern for this tester
In practice, translating a typical Python pattern for testing here comes down to two mechanical swaps: change any (?P<name>...) to (?<name>...), and change any \A or \Z to ^ or $ (leaving the m flag off). Strip the r"..." raw-string wrapper, since that is a Python source-code detail, not part of the pattern text. If the pattern uses re.VERBOSE-style formatting with embedded comments and line breaks, collapse it to a single compact line before testing, then re-format it back into verbose style afterward for readability in your actual Python source. Patterns using possessive quantifiers or atomic groups cannot be tested here directly; validate those specifically inside a Python shell instead.
Common Python regex gotchas
A handful of mistakes show up repeatedly in Python regex code, several of which have nothing to do with the pattern syntax itself and everything to do with how Python's re functions are called.
- re.match only anchors at the start of the string, not the end, so re.match(r"\d+", "123abc") succeeds even though the string is not entirely digits; re.fullmatch or an explicit $ is needed for that
- Forgetting the r prefix on a pattern string containing backslashes, so \d becomes an escape sequence Python's string parser tries to interpret before the regex engine ever sees the pattern
- Mixing up backreference syntax in replacement strings: re.sub uses \1 or \g<name>, not JavaScript's $1 or $<name>
- Compiling the same pattern repeatedly inside a hot loop instead of calling re.compile once outside it, which is a performance issue rather than a correctness one but is easy to miss
Frequently asked questions
Does this tester actually run Python's re module?
No. It runs JavaScript's RegExp engine in your browser, which matches the same core regex features as Python's re module but uses different syntax for a few things, most notably named groups and string anchors. The page calls out those differences directly so you can translate confidently.
How do I test Python named groups (?P<name>...) here?
Rewrite (?P<name>...) as (?<name>...), the JavaScript named-group syntax, before pasting it in. The matching behavior is otherwise the same; only the delimiter around the group name differs.
Can I test re.VERBOSE patterns on this page?
Not directly, since JavaScript has no verbose mode. Collapse the pattern to its compact, single-line form (removing whitespace and # comments meant only for readability) to test it here, then keep the verbose, commented version in your actual Python source.
What is the difference between Python re and JavaScript regex?
The core matching model is very similar, but Python uses (?P<name>...) for named groups where JavaScript uses (?<name>...), Python has \A/\Z anchors JavaScript lacks, and Python 3.11+ supports possessive quantifiers and atomic groups that JavaScript does not have native syntax for.
Does re.match behave differently from a JavaScript regex test?
Yes. Python's re.match only anchors at the start of the string and lets the rest run free, while re.fullmatch and JavaScript's ^...$ (without the m flag) both require the entire string to match. Being clear about which one you actually want avoids a common source of false positives.
Is \d in Python the same as \d in JavaScript?
For plain ASCII digits, yes, both match 0-9. Behavior can differ on Unicode digits from other scripts depending on flags and module settings on the Python side, so treat that edge case as worth testing directly in Python rather than assuming parity.
Can I test Python's re.sub replacement strings here?
This tool shows you the matched groups, which tells you what \1, \2 or \g<name> would resolve to in re.sub, but it does not execute re.sub itself, since that is Python-specific replacement syntax, not part of the shared matching engine.
Why does my pattern with possessive quantifiers fail here?
Possessive quantifiers (*+, ++, ?+) and atomic groups ((?>...)) were added to Python 3.11's re module, but JavaScript's RegExp engine, which powers this tester, has no native equivalent syntax, so those patterns cannot be entered as-is.