DevToolsmith

Regex Tester

Write a regular expression and see every match highlighted in your test text as you type, with numbered/named capture groups, previous/next match navigation and a live replace preview. Expand the explanation to read the pattern token by token. Uses JavaScript’s regex engine, the same as browsers and Node.js.

Runs 100% in your browser — nothing is uploaded

//g
Flags

Expression explanation · JavaScript

Read the expression from left to right. Quantifiers apply to the preceding atom or group.

(?<user>
Start a named capturing group.
[\w.+-]
Character class: match a character in this set; ranges follow the active Unicode mode.
+
One or more repetitions of the preceding atom; greedy matching.
)
End the current group.
@
Match the literal "@".
(?<domain>
Start a named capturing group.
[\w-]
Character class: match a character in this set; ranges follow the active Unicode mode.
+
One or more repetitions of the preceding atom; greedy matching.
(?:
Start a non-capturing group.
\.
Escaped character or syntax: \..
[\w-]
Character class: match a character in this set; ranges follow the active Unicode mode.
+
One or more repetitions of the preceding atom; greedy matching.
)
End the current group.
+
One or more repetitions of the preceding atom; greedy matching.
)
End the current group.

JavaScript RegExp semantics. This explanation does not execute the pattern or prove it safe from excessive backtracking.

Active flags: g. g = all matches, i = case-insensitive, m = multiline anchors, s = dotAll, u/v = Unicode mode, y = sticky, d = match indices.

Nested repetitions can cause excessive backtracking on some inputs. Test with the cancellable regex tool.

Use it in code

JavaScript
const re = /(?<user>[\w.+-]+)@(?<domain>[\w-]+(?:\.[\w-]+)+)/g;
const matches = [...text.matchAll(re)];
Python
import re

pattern = re.compile(r"(?P<user>[\w.+-]+)@(?P<domain>[\w-]+(?:\.[\w-]+)+)")
matches = pattern.findall(text)
Go
re := regexp.MustCompile(`(?<user>[\w.+-]+)@(?<domain>[\w-]+(?:\.[\w-]+)+)`)
matches := re.FindAllString(text, -1)

Python and Go use different regex engines: Go (RE2) has no lookarounds or backreferences, and Python writes named groups as (?P<name>…). Test them with the Python and Go regex testers.

Regex cheat sheet

SyntaxMeaning
. Any character except a line break (with the s flag, including line breaks)
\d \w \s Digit, word character [A-Za-z0-9_], whitespace
\D \W \S Not a digit, not a word character, not whitespace
[abc] [^abc] [a-z] Any of a, b or c; anything except them; a range
^ $ Start and end of the input (of each line with the m flag)
\b Word boundary
* + ? 0 or more, 1 or more, 0 or 1
{3} {2,} {2,5} Exactly 3, at least 2, between 2 and 5
*? +? ?? Lazy versions: match as few as possible
(abc) Capturing group, referenced as $1 in replacements
(?<name>abc) Named group, referenced as $<name>
(?:abc) Group without capturing
a|b a or b
(?=abc) (?!abc) Lookahead: followed by / not followed by abc
(?<=abc) (?<!abc) Lookbehind: preceded by / not preceded by abc
\1 \k<name> Backreference to a group’s match
\p{L} \p{Emoji} Unicode property classes (needs the u flag)

Special characters . * + ? ^ $ { } ( ) [ ] | \ must be escaped with a backslash to match literally.

Common patterns

PatternRegex
Email (practical)
Rejects obvious mistakes; real validation is sending an email.
^[^\s@]+@[^\s@]+\.[^\s@]+$
URL
Finds http and https links in text.
https?:\/\/[^\s/$.?#].[^\s]*
IPv4 address
Each octet 0–255.
\b(?:(?:25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|1?\d?\d)\b
ISO date
YYYY-MM-DD. Doesn’t check that Feb 30 is impossible.
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])
Hex color
#fff or #1e90ff.
#(?:[0-9a-fA-F]{3}){1,2}\b
UUID
Use the i flag for uppercase.
[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}
Semantic version
Groups capture major, minor and patch.
\bv?(\d+)\.(\d+)\.(\d+)(?:-[\w.]+)?\b
Trailing whitespace
Use with the g and m flags, and replace with nothing.
[ \t]+$

Avoid catastrophic backtracking

A regex like ^(\w+\s?)+$ looks harmless, but on a long string that almost matches, the engine tries every way of splitting it between the inner and outer +, which takes exponential time. Try it above on aaaaaaaaaaaaaaaaaaaaaaaaaaaa! and the tester will stop it. To stay safe:

  • Don’t nest quantifiers over the same characters: write ^[\w\s]+$ instead.
  • Prefer specific classes like [^"]* over .*.
  • Limit input length before matching user-supplied text on a server.

Using regular expressions in JavaScript

const re = /(?<year>\d{4})-(?<month>\d{2})/g;
const text = 'Released 2024-05, updated 2026-10';

re.test(text);                           // true
text.match(re);                          // ['2024-05', '2026-10']
for (const m of text.matchAll(re)) {
  console.log(m.index, m.groups.year);   // 9 '2024', then 26 '2026'
}
text.replace(re, '$<month>/$<year>');    // 'Released 05/2024, updated 10/2026'

// Escape user input before putting it in a regex
const escape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

A regex with the g flag remembers lastIndex between calls, so calling re.test() twice on the same string can return true then false. Create a new regex or reset re.lastIndex = 0.

Frequently asked questions

Which regex flavor does this tester use?

JavaScript (ECMAScript), using your browser’s own engine, so results match what your code does in Chrome, Firefox, Safari, Node.js and Deno. Most syntax is shared with PCRE, Python and Java; the differences are mainly in lookbehind support, named group syntax and flags.

What do the regex flags mean?

g finds all matches instead of the first. i ignores case. m makes ^ and $ match at the start and end of every line. s lets . match line breaks. u enables full Unicode, including \p{…} classes and emoji as single characters. y (sticky) only matches at the current position.

Why does the tester say my pattern was stopped?

Patterns with nested quantifiers like (a+)+, (.*)* or (\w+\s?)+$ can take exponential time on some inputs, called catastrophic backtracking. The tester runs your regex in a background worker and stops it after 1.5 seconds. In production the same pattern could freeze a browser tab or take down a server (ReDoS).

How do I use capture groups in a replacement?

Use $1, $2 … for numbered groups, $<name> for named groups, $& for the whole match and $$ for a literal dollar sign. Turn on Replace in the tester to preview the result. In Python the syntax is \1 and \g<name>.

Why does my regex work here but not in Go?

Go’s regexp package uses RE2, which guarantees linear time by leaving out lookaheads, lookbehinds and backreferences. Patterns using (?=, (?!, (?<=, (?<! or \1 won’t compile in Go. Rewrite them with extra capture groups or code logic.