Regex Tester
Test a regular expression against your own text, see every match and capture group, and read back in plain English what the pattern actually says.
Runs entirely in your browser. Nothing you type is uploaded.
Result
3 matches in 111 characters, with 3 capture groups.
- Match 1index 8–2315 chars
ada@example.comGroup Value 1 ada 2 example 3 com - Match 2index 27–4114 chars
grace@navy.milGroup Value 1 grace 2 navy 3 mil - Match 3index 52–6917 chars
help@devbox.toolsGroup Value 1 help 2 devbox 3 tools
What this pattern says
(\w+)Capture group 1The matched text is available as match[1].\wAny word character — a letter, a digit, or an underscore↳ Repeated one or more times, greedily — matching as many as possible
@The character "@"(\w+)Capture group 2The matched text is available as match[2].\wAny word character — a letter, a digit, or an underscore↳ Repeated one or more times, greedily — matching as many as possible
\.The character "."(\w{2,})Capture group 3The matched text is available as match[3].\wAny word character — a letter, a digit, or an underscore↳ Repeated 2 or more times, greedily — matching as many as possible
Flags: global.
Common patterns
Each one loads with example text, and each comes with a note on what it does not handle. Treat them as starting points, not as answers.
Web
Text
Numbers
Dates and times
Code
How to use it
- Type your pattern in the top box — without the surrounding slashes, since the tool supplies those.
- Set the flags.
gfinds every match rather than the first;iignores case;mmakes^and$work per line. - Paste the text you want to test against.
- Read the result panel for matches and capture groups, then the explanation panel to check the pattern says what you think it says.
Everything updates as you type. If a pattern is invalid you get the engine’s message plus a translation of what to do about it — “An opening ( has no matching )” rather than just “Unterminated group”.
The syntax, briefly
Enough to work from. The full regex cheat sheet covers every token with worked examples.
Matching a kind of character
| Token | Matches | Example |
|---|---|---|
. | Any character except a line break | a.c matches abc, a c |
\d \D | A digit / anything but a digit | \d\d matches 42 |
\w \W | Letter, digit or underscore / the opposite | \w+ matches user_1 |
\s \S | Whitespace / non-whitespace | \s+ matches a run of spaces |
[abc] | Any one of the listed characters | [aeiou] matches a vowel |
[^abc] | Any character except those listed | [^0-9] matches a non-digit |
[a-z] | A range | [a-f0-9] matches a hex digit |
Saying how many
| Token | Repeats | Note |
|---|---|---|
* | Zero or more | Can match nothing at all — easy to overlook |
+ | One or more | Requires at least one |
? | Zero or one | Makes the previous item optional |
{3} {2,} {2,5} | Exactly / at least / between | Explicit counts |
*? +? | The same, but lazy | Matches as few as possible — the fix when .* swallows too much |
Position and structure
| Token | Meaning |
|---|---|
^ $ | Start / end of the string — or of each line with the m flag |
\b | A word boundary. Matches a position, not a character |
(…) | Capture group — numbered, and returned in the result |
(?:…) | Group without capturing. Use when you only need grouping |
(?<name>…) | Named capture group, available as match.groups.name |
a|b | Either. The first alternative that matches wins, so order matters |
(?=…) (?!…) | Followed by / not followed by, without consuming it |
The same pattern in other languages
This page runs JavaScript’s engine. Most patterns transfer, but the differences below are the ones that actually break things when a pattern is copied across.
JavaScript
const re = /\d+/g; // or new RegExp("\\d+", "g")- This is the engine running on this page, so what you see here is exactly what JavaScript does.
- No possessive quantifiers (a++) and no atomic groups ((?>…)). Attempts to use them are syntax errors.
- No inline flag groups such as (?i:…) — flags apply to the whole pattern.
- Lookbehind is supported and is variable-length, unlike several other engines.
- \p{…} Unicode property escapes require the u or v flag.
Flags: g — find all matches · i — ignore case · m — ^ and $ match at line boundaries · s — . matches line breaks · u / v — Unicode mode · y — sticky, match only at lastIndex · d — record match indices
Python (re)
import re
re.findall(r"\d+", text)- Named groups are written (?P<name>…), not (?<name>…). This is the single most common cause of a JavaScript pattern failing when pasted into Python.
- Backreferences to named groups are (?P=name).
- Lookbehind must be fixed-width — (?<=ab) is fine, (?<=a+) is an error.
- Use raw strings (r"…") or every backslash needs doubling.
- \d and \w match non-ASCII digits and letters by default; pass re.ASCII to restrict them.
Flags: re.IGNORECASE (re.I) · re.MULTILINE (re.M) · re.DOTALL (re.S) — the equivalent of the s flag · re.VERBOSE (re.X) — allows whitespace and comments in the pattern · Inline form: (?i), (?m), (?s), (?x) at the start of the pattern
Java
Pattern p = Pattern.compile("\\d+");- Patterns are Java strings, so every backslash is doubled: \\d, not \d. Miss this and you get a compile error or a wrong match.
- Supports possessive quantifiers (a++) and atomic groups ((?>…)), neither of which exists in JavaScript.
- matches() requires the whole input to match; use find() for a search. This trips up people expecting JavaScript test() semantics.
- Lookbehind must be bounded — (?<=a{1,5}) is allowed, (?<=a*) is not.
Flags: Pattern.CASE_INSENSITIVE · Pattern.MULTILINE · Pattern.DOTALL · Pattern.UNICODE_CASE · Inline form: (?i), (?m), (?s)
Go (RE2)
re := regexp.MustCompile(`\d+`)- RE2 has no lookahead, no lookbehind, and no backreferences — by design. A pattern using any of them will not compile.
- The trade-off is a guarantee of linear time: RE2 cannot suffer catastrophic backtracking, which is why it is used for untrusted patterns.
- Named groups are (?P<name>…), as in Python.
- Use backtick strings so backslashes are not double-escaped.
Flags: Inline only: (?i), (?m), (?s), (?U) for ungreedy · Example: (?i)hello
PCRE (PHP, and many tools)
preg_match_all('/\d+/', $text, $matches);- The pattern is wrapped in delimiters — usually / … / — and the delimiter itself must be escaped inside the pattern.
- Supports possessive quantifiers, atomic groups, recursion, and \A \z \Z anchors, none of which JavaScript has.
- \Z matches before a trailing line break; \z matches only at the absolute end. JavaScript $ without the m flag behaves like \Z.
- Inline flag groups such as (?i:…) work.
Flags: i, m, s, x — after the closing delimiter, e.g. /pattern/i · u — UTF-8 mode · x — extended, allowing whitespace and comments
.NET
var re = new Regex(@"\d+");- Use verbatim strings (@"…") or every backslash needs doubling.
- Lookbehind is variable-length and can even be infinite, which is more permissive than any other engine here.
- Supports both (?<name>…) and (?'name'…) for named groups.
- Numbering with named groups is unusual: unnamed groups are numbered first, then named ones. Mixing the two changes the indices of the unnamed groups.
- Supports balancing groups, a .NET-only feature for matching nested structures.
Flags: RegexOptions.IgnoreCase · RegexOptions.Multiline · RegexOptions.Singleline — the equivalent of the s flag · RegexOptions.IgnorePatternWhitespace · RegexOptions.NonBacktracking — an RE2-style linear-time engine
Writing a regex that stays fast
Regex performance is almost entirely about backtracking — how many dead ends the engine explores before giving up. Four habits cover most of it:
- Never nest quantifiers.
(a+)+and(a*)*create exponentially many ways to fail. This is the classic denial-of-service pattern. - Prefer a negated class to a lazy dot.
[^"]*beats.*?because it cannot backtrack at all. - Anchor when you can.
^tells the engine not to retry at every position in the string. - Put the cheapest alternative first. Alternation is tried left to right.
If the tool reports that matching timed out, you have reproduced the problem on your own machine — which is much better than reproducing it in production.
Frequently asked questions
Is my test data uploaded anywhere?
No. The pattern and the text are matched by your own browser’s regex engine, in the tab you are looking at. There is no server that could receive them — you can confirm it by opening your browser’s network tab, or by disconnecting from the network and carrying on.
Which regex flavour does this use?
JavaScript’s, because it runs in your browser. That matters when you are writing a pattern for somewhere else: Go’s RE2 engine has no lookahead, lookbehind or backreferences at all; Python and Go write named groups as (?P<name>…); and Java, PCRE and .NET support possessive quantifiers and atomic groups that JavaScript does not. The tool warns you when your pattern uses something that will not travel.
What does the plain-English explanation actually do?
It parses your pattern and describes each piece in order — what it matches, how many times, and whether it is captured. The point is to catch the gap between what you wrote and what you meant, which is where most regex bugs live. A pattern that matches your three test strings can still be wrong about the fourth.
Why did matching stop early?
Two limits protect the page. Results are capped at 1,000 matches, and matching is abandoned after roughly 800 milliseconds. Hitting the time limit is itself a finding: it means your pattern backtracks heavily on this input, and it will be slow wherever you deploy it too.
What is catastrophic backtracking?
When nested quantifiers give the engine exponentially many ways to fail, a pattern like (a+)+$ can take effectively forever on a couple of dozen characters. It is a real denial-of-service vector when patterns or inputs come from users. The usual fixes are to avoid nesting quantifiers, to make the inner part more specific, or to use a linear-time engine such as Go’s RE2 or .NET’s NonBacktracking mode.
Why does my capture group show "did not participate"?
The group is inside an optional or alternative branch that was not used in this match. In JavaScript that group is undefined rather than an empty string, which is a distinction worth respecting — code that treats them the same tends to break on the first input that skips the branch.
Does the global flag change what matches?
Not what matches, but how much you get back. Without g you get the first match only. With g the engine keeps going from where it left off, which is also why a global regex object carries a lastIndex between calls — a well-known source of bugs when the same regex object is reused across test() calls.
Does it work on a phone?
Yes. That is deliberate: several well-known regex testers say outright that they are not optimised for mobile. Here the inputs stack, results appear directly below them, and every control is a full-size touch target.
Related tools and guides
- DataJSON Formatter and Validator
Prettify, minify and validate JSON — with the exact line and column of any error.
- TimeCron Expression Generator and Parser
Build a schedule visually, or paste one and read it in plain English with the next run times.
- DataJSON to YAML Converter
Convert JSON to YAML and back, with validation in both directions.
- GuideRegex for email addresses in JavaScript
A pattern worth using, what it deliberately misses, and why chasing RFC 5322 is the wrong goal.
- ReferenceRegex Cheat Sheet
Every token with a worked example, plus where the major languages disagree.