Regex Tester

Test JavaScript regular expressions live. See matches, capture groups, and apply replacements as you type.

/ /
Flags: g global · i case-insensitive · m multi-line · s dotAll · u unicode · y sticky

  
Enter input above to see the result.
Use $1, $2 for groups · $& for the whole match · $$ for literal $
Enter input above to see the result.

Match, capture, replace

Regular expressions are dense and unforgiving. The way to write one that actually works is iteratively — pattern, sample text, see what matches, adjust. This tool gives you that loop in your browser using the JavaScript engine's native RegExp, plus capture-group inspection and a replacement preview. Patterns and inputs never leave the page.

Typical starting points

Patterns worth memorising

Flags, greediness, and the JS engine

Catastrophic backtracking and Unicode traps

Reformatting dates with capture groups

Enter the pattern (\d{4})-(\d{2})-(\d{2}) with the g flag against 2026-08-21 and 2025-12-01. Both dates highlight, and the groups panel reads Match 1 at index 0 — full: 2026-08-21, $1: 2026, $2: 08, $3: 21, then Match 2 for the second date. Type $3/$2/$1 into the replacement box and the preview becomes 21/08/2026 and 01/12/2025. Delete the g flag and only the first date matches — a non-global regex stops after one hit.

Single matches, literal dollars, lookbehind errors, and \w scope

Why does my pattern only match once? No g flag. Without it, RegExp.exec returns the first match only. Add g for find-all; add m as well if you want ^ and $ to anchor to each line rather than the whole string.

How do I put a literal $ in the replacement? Write $$. In the replacement field $1/$2 are capture groups and $& is the whole match, so a bare $ has to be escaped as $$.

My lookbehind / atomic group throws an error. This runs the browser's native JavaScript engine, not PCRE. Lookbehind (?<=…) only works in modern engines, and there's no \K, no recursion, and no atomic groups. Patterns lifted from PHP or Python often need adjusting.

Does \w match accented or non-Latin letters? Not by default — \w is ASCII [A-Za-z0-9_] only, so "café" or "中文" won't fully match. Add the u flag and use \p{L} for Unicode-aware letter matching.

Backtracking: why regex is powerful and occasionally explosive

A regex engine walks your pattern against the text one position at a time, and the crucial behaviour is backtracking: quantifiers like * and + are greedy, grabbing as much as they can, then giving characters back when the rest of the pattern fails to match. That give-and-take is what makes regex powerful and also what makes it occasionally explode — nested quantifiers on failing input can force exponential backtracking (catastrophic backtracking), hanging on a string only slightly longer than the ones that worked. Anchors (^ $), character classes, and lazy quantifiers (*?) exist largely to constrain that search and keep it linear.

When regex is the wrong tool entirely

Reaching for regex on nested or recursive structures — HTML, JSON, balanced brackets — which are not regular languages and cannot be matched reliably by a regex, only approximated until an edge case breaks it. Use a real parser for those. The everyday slip is forgetting that . doesn't match newlines by default and that * is greedy, so one unanchored pattern quietly swallows far more than intended.

Related

Keep syntax handy with the regex cheatsheet, clean up model output with the regex for LLM output tool, and compare before/after text in the text diff. The high-leverage subset: the 20% of regex worth learning.