Free tool

Regex tester: test regular expressions live

Type a regular expression and some text: every match and capture group is highlighted as you type. Below the pattern you get a token-by-token explanation, a replace preview with $1 and $<name>, and ready-to-paste code for JavaScript, Python, Go and PHP.

Free · no sign-up · runs in your browser, nothing is uploaded

Regular expression
Test string
Result

No match. Check the flags (case with i, lines with m) or open the explanation below.

Explanation
2 capture groups
  1. (?<user>Capture group 1 named "user"
  2. [\w.+-]One character from: a word character, ".", "+", "-"
  3. +Repeat the previous item one or more times, as many as possible
  4. )End of group 1
  5. @The character "@"
  6. (?<domain>Capture group 2 named "domain"
  7. [\w-]One character from: a word character, "-"
  8. +Repeat the previous item one or more times, as many as possible
  9. (?:Non-capturing group: groups without saving the match
  10. \.The character "."
  11. [\w-]One character from: a word character, "-"
  12. +Repeat the previous item one or more times, as many as possible
  13. )End of group
  14. +Repeat the previous item one or more times, as many as possible
  15. )End of group 2

How to use this regex tester

Write the pattern without the surrounding slashes, or paste a whole literal like /\d+/g and the flags are split out for you. The test string is searched with your browser's own JavaScript engine, so what you see is what new RegExp(pattern, flags) does in your code. Click a match in the list to select it in the text.

The result panel has six views:

  • Matches: each match with its start and end index and every group, numbered and named. Download them as JSON.
  • Replace: the text after text.replace(regex, replacement), live.
  • List: one line per match built from a template, for pulling values out of logs or CSV.
  • Split: the parts from text.split(regex). Capture groups are included in the result, as JavaScript does.
  • Tests: lines that should match and lines that should not, each checked on its own with pass or fail.
  • Code: the same pattern, flags and replacement as JavaScript, Python, Go or PHP.

The Common patterns menu loads tested patterns for emails, URLs, IP addresses, dates, UUIDs, semver and more, with examples that should and should not match. The full list, with every token explained, is on the regex cheat sheet.

JavaScript regex flags

Flags go after the closing slash (/x/gi) or in the second argument of new RegExp("x", "gi"). Click a flag above to toggle it. The u and v flags cannot be used together.

FlagPropertyWhat it does
gglobalFind every match, not just the first.
iignoreCaseIgnore upper and lower case.
mmultiline^ and $ match at the start and end of each line.
sdotAll. also matches line breaks.
uunicodeUnicode mode: code points, \u{...} and \p{...}, stricter syntax.
vunicodeSetsUnicode sets: like u, plus set operations in classes ([\p{L}--[a-z]]).
ystickyMatch only at lastIndex, with no searching ahead.
dhasIndicesReport the start and end of every group (match.indices).

Replacement patterns: $1, $<name> and $&

In String.prototype.replace and replaceAll, the replacement string can refer to parts of the match. The Replace tab applies the same rules, which come from the GetSubstitution step of the ECMAScript spec:

PatternInsertsExample
$&the whole match"cat".replace(/a/, "[$&]") → c[a]t
$1 … $99a numbered capture group"ada lovelace".replace(/(\w+) (\w+)/, "$2, $1") → lovelace, ada
$<name>a named group (?<name>...)"5kg".replace(/(?<n>\d+)kg/, "$<n> kilograms") → 5 kilograms
$`the text before the match"ab-cd".replace(/-/, "$`") → ababcd
$'the text after the match"ab-cd".replace(/-/, "$'") → abcdcd
$$a literal dollar sign"5".replace(/\d/, "$$$&") → $5

A $ that is not followed by one of these is kept as is, and $3 stays literal when the pattern has fewer than 3 groups. For anything more complex, pass a function: text.replace(re, (match, g1, g2) => ...).

Catastrophic backtracking and how this tester stops it

JavaScript's regex engine is a backtracking engine. When a match fails, it goes back and tries every other way the pattern could have matched. For most patterns that is fast. For a pattern like ^(a+)+$ on a line of a's that ends in a b, the number of ways to split the a's between the inner and outer + doubles with every extra character, and the page freezes. On a server, the same pattern can be used to tie up a process with crafted input; OWASP calls this ReDoS.

Here the pattern runs in a web worker. If it takes more than 2 seconds, the worker is stopped and you get a message instead of a frozen tab. The explanation also flags nested quantifiers before you run anything. To fix such a pattern, make each part match in only one way:

// Slow: a group of repeated items, repeated again
/^(\w+\s?)*$/

// Fast: the same text, but the words and spaces cannot overlap
/^\w+(?:\s\w+)*$/

Use your regex in JavaScript, Python, Go and PHP

The Code tab writes this for you. These are the main differences to watch when you move a pattern between languages:

FeatureJavaScriptPython (re)Go (regexp)
Named group(?<name>...)(?P<name>...)(?P<name>...), also (?<name>...) since Go 1.22
Named group in a replacement$<name>\g<name>${name}
Numbered group in a replacement$1\1 or \g<1>${1}
Lookahead and lookbehindYesYes, lookbehind must be fixed widthNo
Backreferences (\1)YesYesNo
FlagsAfter the pattern: /x/giArguments: re.I | re.M, or (?i) at the startInline only: (?i)x
Find all matchesstr.matchAll(re) with gre.finditer(text)re.FindAllString(text, -1)

Go uses the RE2 engine, which guarantees linear time but has no lookarounds or backreferences. PHP's preg_ functions use PCRE and need delimiters around the pattern, like '/\d+/i'. A JavaScript example with all matches and named groups:

const re = /(?<user>[\w.+-]+)@(?<domain>[\w-]+(?:\.[\w-]+)+)/g;
for (const m of text.matchAll(re)) {
  console.log(m.index, m.groups.user, m.groups.domain);
}

Common regex mistakes

  • Double escaping in strings. In new RegExp("\\d+") the backslash must be doubled, because the string literal eats one. The literal /\d+/ needs only one.
  • An unescaped dot. example.com also matches exampleXcom. Write example\.com.
  • [A-z] instead of [A-Za-z]. The range also covers [ \ ] ^ _ and the backtick, which sit between Z and a in ASCII.
  • Forgetting anchors when validating. /\d{5}/.test("abc123456") is true. Use ^\d{5}$ to check the whole value.
  • \w and \b are ASCII only. \w does not match é or ü, even with the u flag. Use \p{L} with the u or v flag for letters in any language.

Building a pattern from user input? Escape it first, or every . and ( in the input becomes regex syntax. The string escape tool has a regex mode. For JSON data, a JSONPath query is often simpler than a regex, and to compare two outputs use the diff checker. More developer tools for testing are in the testing tools directory.

FAQ

How do I test a regular expression?+

Type the pattern between the slashes, pick the flags, and paste some text below. Every match is highlighted as you type, and the Matches tab lists each one with its position and capture groups. Use the Tests tab to keep a list of lines that must match and lines that must not, so you notice when a change breaks a case.

Which regex flavor does this tester use?+

JavaScript (ECMAScript), run by your own browser engine, so results are exactly what new RegExp() gives you in that browser. Most simple patterns work the same in Python, PHP, Java and Go. The Code tab converts the pattern for Python, Go and PHP and adds a note when a feature does not carry over, such as lookarounds in Go.

What does the g flag do in a regex?+

g (global) finds every match instead of stopping at the first one. It also changes how methods behave: str.replace() replaces all matches only with g, str.match() returns all matched strings instead of the first match with its groups, and str.matchAll() requires it.

Why does regex.test() return true, then false, on the same string?+

With the g or y flag, a RegExp object remembers lastIndex, the position where the last match ended. The next test() or exec() call starts searching from there, fails at the end of the text, and resets lastIndex to 0. Drop the g flag when you only need a yes or no, or set re.lastIndex = 0 before each call.

How do I use capture groups in a replacement?+

In JavaScript, write $1, $2 and so on for numbered groups, $<name> for a named group (?<name>...), $& for the whole match and $$ for a literal dollar sign. For example, "2026-10-31".replace(/(\d+)-(\d+)-(\d+)/, "$3/$2/$1") gives "31/10/2026". The Replace tab shows the result live.

What is catastrophic backtracking?+

It is when a pattern can match the same text in a huge number of ways, so the engine tries them all before it gives up. Nested quantifiers like (a+)+ or (\w+\s?)* are the usual cause, and the time can grow exponentially with the length of the text. This tester runs your pattern in a background worker and stops it after 2 seconds, and the explanation warns about nested quantifiers before you even run it.

How do I match any character including a new line?+

Turn on the s (dotAll) flag, so . also matches line breaks. Without it, use [\s\S] or [^], which match any character in any JavaScript engine.

Is my test text sent anywhere?+

No. Matching runs in your browser and nothing is uploaded. Short patterns and texts are kept in the page URL so you can share a link to the exact test; long texts stay out of the URL.

Sources: MDN: Regular expressions · MDN: RegExp · MDN: String.prototype.replace · MDN: RegExp.prototype.lastIndex · ECMAScript: GetSubstitution · Python re · Go regexp/syntax · PHP PCRE · OWASP: ReDoS. Checked October 2026.