Regex Tester
Test regular expressions live with match highlighting, capture groups, and full flag support. Uses Python's re module, with instant browser-side feedback.
Calculator
Highlighted Matches
Match Details
| # | Match | Position | Groups |
|---|
Total Matches
—
Capture Groups
—
Input Length
— chars
Invalid Pattern
—
Result
—
How Regex Tester Works
What is a Regular Expression?
A regular expression (regex) is a pattern language for describing text — used to search, match,
validate, or extract substrings without writing character-by-character parsing logic. Instead of a
loop that checks each character, a single pattern like \d+ means “one or more
digits”, and a regex engine finds every place in your text where that shape occurs. This tool
tests patterns using Python’s standard re module — the same engine Python
itself uses — with live match highlighting, capture group inspection, and full flag support.
Regex Syntax at a Glance
| Symbol | Meaning |
|---|---|
. | Any character except newline (unless Dot-all is on) |
\d \w \s | Digit, word character, whitespace (and \D \W \S for the opposite) |
[abc] | Any one of a, b, or c — a character class |
[^abc] | Any character except a, b, or c |
^ $ | Start / end of string (or line, with Multiline on) |
\b | Word boundary |
* + ? {n,m} | Quantifiers — see below |
( ) (?: ) | Capturing group / non-capturing group |
| | Alternation (OR) |
Flags Explained
- Global — find every match in the text, not just the first. Nearly always
what you want when testing a pattern; off, the engine mirrors Python’s
re.search()(first match only) instead ofre.finditer(). - Case-insensitive (
re.IGNORECASE) —abcmatchesABC,Abc, etc. - Multiline (
re.MULTILINE) —^and$match at the start/end of every line, not just the start/end of the whole string. - Dot-all (
re.DOTALL) —.also matches newline characters, useful when a pattern needs to span multiple lines. - Unicode — on by default, matching Python 3’s normal behavior:
\wmatches any Unicode letter, not justA–Z. Turning it off appliesre.ASCII, restricting\w \d \s \bto ASCII characters only. - Ignore whitespace (
re.VERBOSE) — lets you write a complex pattern across multiple lines with#comments for readability; insignificant whitespace in the pattern is ignored.
Capture Groups
Parentheses ( ) create a capture group — a portion of the match you
can extract separately from the whole. (\w+)@(\w+)\.com matched against
contact: alice@example.com captures group 1 as alice and group 2 as
example, alongside the full match alice@example.com. Prefix a group with
?P<name> — (?P<user>\w+) — to give it a name instead of just a
number, which this tool displays alongside the position-based index. Use (?:...) for a
non-capturing group when you need grouping (for a quantifier or alternation) but don’t need to
extract that portion.
Character Classes
[...] matches any one character from the set inside — [aeiou]
matches a single vowel, [0-9] (equivalent to \d for ASCII digits) matches a
single digit, and [^...] negates the set. Ranges (a-z, A-Z,
0-9) can be combined: [a-zA-Z0-9_] is exactly what \w means in
ASCII mode. Inside a character class, most special characters (. * + ?) lose their special
meaning and become literal.
Anchors
^ and $ anchor a match to the start and end of the string (or each line,
with Multiline on) without consuming any characters themselves. \b anchors to a
word boundary — the transition between a word character and a non-word character —
letting \bcat\b match the word “cat” but not the “cat” inside
“category” or “scatter”.
Quantifiers
| Quantifier | Meaning |
|---|---|
* | Zero or more |
+ | One or more |
? | Zero or one (optional) |
{n} | Exactly n |
{n,} | n or more |
{n,m} | Between n and m, inclusive |
By default quantifiers are greedy — they match as much as possible, then backtrack
if needed. Adding ? after a quantifier (+?, *?) makes it
lazy, matching as little as possible instead.
Common Mistakes
- Forgetting to escape special characters. A literal dot in an IP address or
version number needs
\.— a bare.matches any character. - Greedy quantifiers matching too much.
<.+>against<b>bold</b>matches the entire string (greedy), not just<b>— use the lazy<.+?>instead, or better, a character class that excludes>. - Confusing
matchandsearchsemantics. With Global off, this tool finds only the first match anywhere in the text — it does not require the match to start at position 0. - Nested quantifiers. A pattern like
(a+)+can cause catastrophic backtracking — see Security Notes below. This tool detects and rejects the common form of this before running it. - Assuming Python and JavaScript regex are identical. They're very close but not
the same — Python named groups use
(?P<name>...), JavaScript uses(?<name>...). This tool's live preview uses your browser's JavaScript engine for instant feedback, while the definitive result (after submitting) always uses Python's engine.
Performance Tips
- Prefer specific character classes (
[0-9]) over broad ones (.) — the engine has less to consider at each position. - Anchor patterns with
^when you know a match must start at the beginning — this lets the engine fail fast on non-matching text instead of trying every position. - Avoid nested quantifiers entirely where possible; if you need "one or more repetitions of a variable-length unit," restructure the pattern rather than wrapping a quantified group in another quantifier.
- For very large inputs, consider whether you actually need
re.DOTALLor unanchored matching — both can force the engine to consider substantially more of the string.
Security Notes
Certain patterns — classically nested quantifiers like (a+)+ or
(\d+)+ — can take exponentially longer to fail than to succeed against adversarial input,
a vulnerability class known as ReDoS (Regular Expression Denial of Service). This
tool statically detects the common nested-quantifier shape and rejects it before execution, and caps
test text at 50,000 characters as additional defense in depth. This detection is not
exhaustive — alternation-based catastrophic patterns with overlapping branches
((a|a)+) are not caught, because no shallow syntax check can distinguish that from safe
alternation like (cat|dog)+ without incorrectly flagging legitimate patterns. If you're
building a regex that will run against untrusted input in production code, treat this tool's check as
a helpful sanity net, not a substitute for understanding backtracking behavior yourself.
Worked Examples
| Goal | Pattern |
|---|---|
| Email address (simplified) | [\w.+-]+@[\w-]+\.[a-zA-Z]{2,} |
| Indian PIN code | ^\d{6}$ |
| Hex color code | #[0-9a-fA-F]{6}\b |
| Whitespace-trimmed line | ^\s*(.*?)\s*$ |
| Words only, no digits | \b[^\d\W]+\b |
Related Tools
Once you've extracted or validated data with a regex, you'll often want to reshape it further: format the result as JSON, verify it with the JSON Validator, percent-encode it for a URL, or check whether it's part of a JWT or Base64-encoded value.
Accuracy & Sources
Last reviewed: July 2026. Formula source: Python re module documentation (Python Software Foundation). All calculations run in your browser. No data is sent to any server.
Frequently Asked Questions
Both, for different purposes. The definitive result — what you get after submitting the form, and what always renders correctly even with JavaScript disabled — uses Python's standard re module. For instant feedback as you type, this tool also runs a live preview in your browser using JavaScript's native regex engine, which is very close to Python's but not identical (see the named-groups syntax difference below). When the two might disagree, trust the submitted result.
Python named groups use (?P<name>...), but JavaScript's native regex syntax uses (?<name>...) without the P. This tool's live preview runs in your browser using JavaScript's regex engine, so a Python-style named group will show 'Invalid Pattern' in the live view even though it's perfectly valid — submit the form and the server-side Python engine will process it correctly.
With Global on (the default), the tool finds every non-overlapping match in your text — equivalent to Python's re.finditer(). With Global off, it finds only the first match anywhere in the text — equivalent to re.search(), which does NOT require the match to start at the very beginning of the string (that's what the ^ anchor is for).
This tool detects patterns with a quantified group wrapping another quantifier — the classic shape (a+)+, (\d+)+, (x*)* — and rejects them before execution, because against certain input they can take exponentially long to evaluate and could freeze your browser or hang a server. This check isn't exhaustive (alternation-based cases like (a|a)+ aren't caught), but it stops the most common real-world cause. Try restructuring the pattern to avoid nesting one quantified group inside another.
Turn on the Multiline flag, which makes ^ and $ match the start and end of each individual line rather than only the very start and end of the whole text. If you also want . to match newline characters (so a pattern can span across lines), turn on Dot-all as well — these are two separate, independent flags.
Case-insensitive (re.IGNORECASE) controls whether 'ABC' matches 'abc'. Unicode (on by default) controls whether \w, \d, and \s match only ASCII characters or any Unicode letter/digit/whitespace — turning Unicode off applies re.ASCII, so \w+ against 'café' matches only 'caf', not the é. They're independent settings that affect completely different aspects of matching.
Live testing runs entirely in your browser via JavaScript as you type — nothing leaves your device for that. Submitting the form does send the pattern and text to get the authoritative Python-based result (and works even with JavaScript disabled), but that request is processed and returned without being stored or logged.