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.
Match results will appear here after clicking Test...
How it works
- Enter a pattern: Type a JavaScript regular expression. The pattern is passed to
new RegExp()— do not include the surrounding slashes. - Select flags: Check the flags you need. The g flag is selected by default to find all matches.
- Enter test text: Paste or type the text you want to search.
- Click Test: The tool runs
exec()on your text and displays all matches with their positions, matched text, and any capture groups. - Copy matches: Click "Copy matches" to copy the match list in a simple
index-end: textformat.
JavaScript regex flags
| Flag | Name | Effect |
|---|---|---|
| g | global | Find all matches, not just the first. |
| i | ignoreCase | Case-insensitive matching. |
| m | multiline | ^ and $ match line boundaries, not just string start/end. |
| s | dotAll | . matches newline characters. |
| u | unicode | Full Unicode matching. . matches emoji as one character. |
| y | sticky | Match 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}\bTest 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'); // falseString.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 8The 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: SpainPython 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: SpainNamed 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.