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.

Contact ada@example.com or grace@navy.mil. Support: help@devbox.tools Not an address: @example or ada@localhost
  • Match 1index 8–2315 chars
    ada@example.com
    GroupValue
    1ada
    2example
    3com
  • Match 2index 27–4114 chars
    grace@navy.mil
    GroupValue
    1grace
    2navy
    3mil
  • Match 3index 52–6917 chars
    help@devbox.tools
    GroupValue
    1help
    2devbox
    3tools

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

  1. Type your pattern in the top box — without the surrounding slashes, since the tool supplies those.
  2. Set the flags. g finds every match rather than the first; i ignores case; m makes ^ and $ work per line.
  3. Paste the text you want to test against.
  4. 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

TokenMatchesExample
.Any character except a line breaka.c matches abc, a c
\d \DA digit / anything but a digit\d\d matches 42
\w \WLetter, digit or underscore / the opposite\w+ matches user_1
\s \SWhitespace / 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

TokenRepeatsNote
*Zero or moreCan match nothing at all — easy to overlook
+One or moreRequires at least one
?Zero or oneMakes the previous item optional
{3} {2,} {2,5}Exactly / at least / betweenExplicit counts
*? +?The same, but lazyMatches as few as possible — the fix when .* swallows too much

Position and structure

TokenMeaning
^ $Start / end of the string — or of each line with the m flag
\bA 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|bEither. 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.