JavaScript Regex Tester

Test JavaScript regular expressions in your browser. See matches highlighted with capture groups and positions. Nothing uploaded.

Test JavaScript regular expressions with match highlighting. Enter a pattern and test string, then click Test to see all matches with their positions and capture groups. Supports all JavaScript regex flags: g (global), i (case-insensitive), m (multiline), s (dotAll), u (unicode), and y (sticky). Uses JavaScript's native RegExp engine — not PCRE or Python regex. All testing runs locally in your browser.

Patternnew RegExp("", "g")
Test string
Matches

Match results will appear here after clicking Test...

How it works

  1. Enter a pattern: Type a JavaScript regular expression. The pattern is passed to new RegExp() — do not include the surrounding slashes.
  2. Select flags: Check the flags you need. The g flag is selected by default to find all matches.
  3. Enter test text: Paste or type the text you want to search.
  4. Click Test: The tool runs exec() on your text and displays all matches with their positions, matched text, and any capture groups.
  5. Copy matches: Click "Copy matches" to copy the match list in a simple index-end: text format.

JavaScript regex flags

FlagNameEffect
gglobalFind all matches, not just the first.
iignoreCaseCase-insensitive matching.
mmultiline^ and $ match line boundaries, not just string start/end.
sdotAll. matches newline characters.
uunicodeFull Unicode matching. . matches emoji as one character.
ystickyMatch must start exactly at lastIndex position.

Common regex patterns

Email address (simple)

[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}

URL (http/https)

https?://[^\s]+

Phone number (US)

\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}

IPv4 address

\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b

Test a regex in JavaScript

JavaScript provides several methods for working with regular expressions. Each behaves differently depending on whether you need a boolean check, match details, or iteration over all matches.

RegExp.prototype.test()

Returns true if the pattern matches anywhere in the string, false otherwise. Fast for simple existence checks.

const regex = /\d+/;
regex.test('abc123'); // true
regex.test('no digits'); // false

String.prototype.match() and matchAll()

match() returns an array of matches. Without the g flag, it includes capture groups; with g, it returns all matched strings but no groups. Use matchAll() to get an iterator with full match details for each occurrence.

'abc 123 def 456'.match(/\d+/);   // ['123']
'abc 123 def 456'.match(/\d+/g);  // ['123', '456']

// matchAll returns an iterator with groups
[...'abc 123 def 456'.matchAll(/(\d+)/g)]
// [{ 0: '123', 1: '123', index: 4 }, ...]

RegExp.prototype.exec()

Returns detailed match information including index and capture groups. With the g flag, call it repeatedly to iterate through all matches (this tool uses exec() internally).

const regex = /(\d+)/g;
const str = 'a1 b22 c333';
let match;
while ((match = regex.exec(str)) !== null) {
  console.log(match[0], 'at', match.index);
}
// '1' at 1, '22' at 4, '333' at 8

The g-flag lastIndex gotcha

When a regex has the g or y flag, test() and exec() update lastIndex after each match. The next call continues from that position, which can cause unexpected alternating results:

const regex = /a/g;
regex.test('aaa'); // true, lastIndex = 1
regex.test('aaa'); // true, lastIndex = 2
regex.test('aaa'); // true, lastIndex = 3
regex.test('aaa'); // false, lastIndex = 0 (reset)

To avoid this, either reset lastIndex = 0 before each test, drop the g flag if you only need a boolean check, or create a fresh regex for each call.

Regex in Python and Node

The snippets below run \b([A-Z][a-z]+)\b on Ada wrote Notes in Spain, not yaml. — the same pattern this page documents. Node calls new RegExp and loops exec() with the g flag, same as this page. CPython re.finditer is a different engine (not ECMAScript and not PCRE). Both print the same three matches on this ASCII string. For flags and lookbehind vs PCRE, see JavaScript RegExp vs PCRE: Flags and Lookbehind.

Node.js with new RegExp

This is the same ECMA-262 RegExp this page uses. With g, exec() advances lastIndex — reset it to 0 or construct a new regex before a second pass. On an empty match this page increments lastIndex by 1 so the loop cannot stall:

const re = new RegExp('\\b([A-Z][a-z]+)\\b', 'g');
const text = 'Ada wrote Notes in Spain, not yaml.';
let match;
while ((match = re.exec(text)) !== null) {
  console.log(match.index + '-' + (match.index + match[0].length) + ': ' + match[0]);
}
// 0-3: Ada
// 10-15: Notes
// 19-24: Spain

Python with re.finditer

re.finditer yields match objects with start, end, and groups — the closest stdlib iterator to this page's exec() loop. re.findall with a group returns only ['Ada', 'Notes', 'Spain'] with no indexes. re.match anchors at the start of the string; this page searches anywhere:

import re

text = 'Ada wrote Notes in Spain, not yaml.'
for m in re.finditer(r'\b([A-Z][a-z]+)\b', text):
    print(f'{m.start()}-{m.end()}: {m.group(0)}')
# 0-3: Ada
# 10-15: Notes
# 19-24: Spain

Named groups are (?<name>...) in JavaScript and (?P<name>...) in Python — the JS form is a syntax error in re. Flag i is re.IGNORECASE, m is re.MULTILINE, and s is re.DOTALL. There is no Python flag for sticky y. JavaScript \w stays [A-Za-z0-9_] even with u, so \b around café matches caf here; CPython re matches café unless you pass re.ASCII. Lookbehind may be variable-length in JavaScript; Python requires a fixed width. For Unicode code points vs code units, see Unicode normalize.

Regex in the shell

POSIX grep is line-oriented. Default patterns are BRE; -E is ERE. A matching line is printed in full. GNU and BSD grep -o print each match; -o is not in POSIX.1-2024 grep. This page is ECMA-262 RegExp and writes index-end: text. GNU grep 3.11 -oE '\b([A-Z][a-z]+)\b' on Ada wrote Notes in Spain, not yaml. prints Ada, Notes, and Spain — the same three strings this page highlights, without 0-3 / 10-15 / 19-24. \b is a GNU word boundary, not POSIX ERE. POSIX has no \b, \w, \d, lookahead, or lookbehind.

GNU grep (Linux)

GNU grep 3.11 treats \b as a word boundary in both BRE and ERE. -o lists matches; omit it and the whole line is printed. GNU ERE \d is a literal d (dad is two d hits; a1 b22 does not match). This page's \d is [0-9]. Use [[:digit:]] for a portable digit class:

printf '%s\n' 'Ada wrote Notes in Spain, not yaml.' \
  | grep -oE '\b([A-Z][a-z]+)\b'
# Ada
# Notes
# Spain

printf '%s\n' 'Ada wrote Notes in Spain, not yaml.' \
  | grep -E '\b([A-Z][a-z]+)\b'
# Ada wrote Notes in Spain, not yaml.

printf '%s\n' 'a1 b22' | grep -oE '[[:digit:]]+'
# 1
# 22

POSIX grep (no -o)

A strictly conforming grep -E has no match-only switch and no \b. The character-class form still selects the same ASCII line because Ada, Notes, and Spain sit on one line. It does not emit this page's indexes, and it cannot walk lastIndex:

printf '%s\n' 'Ada wrote Notes in Spain, not yaml.' \
  | grep -E '[A-Z][a-z]+'
# Ada wrote Notes in Spain, not yaml.

GNU grep -P is PCRE, not this page and not POSIX. Named groups (?<name>...) and lookbehind work here and in -P; GNU ERE warns and matches nothing. GNU sed 4.9 -E s/\b([A-Z][a-z]+)\b/[\1]/g wraps the same three words; POSIX sed is BRE unless -E is available (POSIX.1-2024). grep -i is this page's i. There is no POSIX flag for sticky y, unicode u, or dotAll s. In en_US.UTF-8, GNU grep 3.11 treated é as in [a-z] / \w, so Café matched as one word. LC_ALL=C wrote Caf, matching this page. C.UTF-8 missed Café entirely. This page's \w stays [A-Za-z0-9_] even with u. For flags and lookbehind vs PCRE, see JavaScript RegExp vs PCRE: Flags and Lookbehind.

FAQ

What regex syntax does this tool use?
This tool uses JavaScript's native RegExp engine (ECMAScript). It supports standard regex features like character classes, quantifiers, groups, lookahead, and lookbehind. It is not PCRE, Python re, or POSIX regex — some syntax differences exist between engines.
What do the regex flags mean?
g (global) finds all matches. i (ignoreCase) makes matching case-insensitive. m (multiline) makes ^ and $ match line boundaries. s (dotAll) makes . match newlines. u (unicode) enables full Unicode matching so emoji like 😀 are treated as one character. y (sticky) anchors each match to lastIndex.
Why does my regex match differently with the u flag?
Without the u flag, JavaScript treats strings as sequences of UTF-16 code units. Emoji and other characters outside the BMP are two code units each, so . matches half an emoji. With u, . matches whole Unicode code points correctly.
Why does test() return different results each time with the g flag?
With g or y flags, RegExp.test() and exec() update lastIndex after each match. The next call starts from that position, not from 0. Reset lastIndex to 0 before reusing a global regex, or create a new RegExp each time.
How are capture groups shown?
Capture groups appear after each match. Numbered groups are match[1], match[2], etc. Named groups (like (?<name>...)) appear in match.groups. This tool displays both.
Does this tool upload my data?
No. All regex testing runs entirely in your browser using JavaScript's native RegExp. Your patterns and test strings are never sent to a server.

Related