Regex Tester

Test JavaScript regular expressions against your own text. Toggle the g, i, m, s and u flags, inspect every match with its index and capture groups, and preview the replacement result live.

See every match, every group and every index as you type. Enter a pattern and some text to match against. Each result is listed with its position and capture groups, invalid patterns report the engine's own error message, and the replacement field shows exactly what a replace call would produce.

/ / g
Matches

Reading a regular expression the way the engine does

Flags change the meaning, not just the search

The five flags are not preferences, they redefine the pattern. Without g, a search returns the first match and stops; with it, the engine keeps a lastIndex cursor and walks the whole string, which is also why a global regex reused across calls can appear to skip matches. The i flag folds case using Unicode case mapping rather than a simple ASCII shift.

The two most misunderstood are m and s. m changes only what ^ and $ mean, anchoring them to line boundaries rather than the whole string; it does nothing to .. Conversely s changes only ., letting it match a newline. The name "dotall" is the useful one to remember. The u flag makes the pattern operate on code points instead of UTF-16 units, so . matches an emoji as one unit and \u{1F600} escapes become legal. It also makes previously tolerated escapes an error, which is why an existing pattern can break the moment you add it.

Groups, indices and replacement

Every parenthesised section captures by default, numbered by the order of its opening bracket, and those numbers are what $1 and $2 refer to in a replacement. Nesting follows the same rule, so in ((a)b) group one is ab and group two is a. When you only need grouping for alternation or repetition, (?:...) avoids allocating a capture and keeps the numbering readable.

The index reported for each match is the offset of the first matched character, which matters more than it sounds. It lets you distinguish two identical matches at different positions, confirm that an anchor did what you expected, and diagnose the classic zero-length match. A pattern such as \d* matches the empty string everywhere, so a global scan finds a match at every position; the engine only advances because implementations force the cursor forward when the match is empty.

Backtracking and the match limit

Most engines, including JavaScript's, use backtracking. When part of the pattern fails, the engine returns to the last decision point and tries another path. Usually this is invisible. It becomes catastrophic when nested quantifiers make the number of paths grow exponentially, the classic shape being (a+)+b against a long run of a characters with no b. That input can hang a browser tab, and if the pattern comes from user input it becomes a denial-of-service vector.

Two habits avoid almost all of it: prefer specific character classes over .* so alternatives cannot overlap, and anchor patterns where you can, since an anchored failure is rejected immediately instead of being retried at every offset. This tool also caps results at 500 matches and tells you when it truncated, so a runaway pattern degrades into a slow result rather than a frozen page.

Open-source note: implemented in vanilla JavaScript with no third-party libraries.

FAQ

Which regex flavour does this use?
JavaScript, meaning the ECMAScript engine built into your browser. Perl, PCRE and Python patterns are close but differ in lookbehind, named groups and some escapes.
What does the g flag actually change?
Without it you get only the first match. With it the engine scans the whole string and returns every match, which is what fills the list here.
Why do I get empty matches?
Your pattern can match zero characters, as `\d*` does. A global scan then reports a match at every position, and the engine steps forward manually to avoid looping.
How do I reference capture groups in the replacement?
Use $1 for the first group, $2 for the second, and $& for the whole match. Write $$ if you need a literal dollar sign.
What does "showing the first 500" mean?
The result list is capped at 500 matches so a very broad pattern cannot freeze the page. The replacement preview still applies to the entire text.
Why does my pattern make the page slow?
Nested quantifiers like (a+)+ cause exponential backtracking. Use specific character classes instead of .* and anchor the pattern to keep matching linear.