JavaScript Regex Tester
Write a regular expression, paste test text, and see live match highlights with capture group details. Runs entirely in your browser.
Quick Examples
How This Regex Tester Works β And How to Read Its Output
What This Tool Actually Does
This is a live JavaScript regular expression tester. You type a pattern into the /pattern/ field, choose flags, and paste text into the test string box β the tool then runs your pattern against that text using the browser's built-in RegExp engine and shows you every match, the character index where each match starts, and any capture groups it contains. Nothing is sent to a server: pattern compilation and matching both happen with useMemo in your browser, so results update instantly as you type.
Internally, the tool always enumerates matches by calling regex.exec() in a loop against your test string, advancing lastIndex after each match (and manually bumping it by one when a match has zero length, to avoid an infinite loop on patterns like x*). The loop is capped at 500 matches as a safety guard. If your pattern is invalid β an unbalanced parenthesis, a bad quantifier, an unsupported escape β the tool catches the thrown SyntaxError and shows the exact JavaScript error message under the pattern field instead of crashing.
How to Use It
- Type or paste your pattern between the two forward slashes β no need to include the slashes yourself, they're just visual delimiters.
- Toggle flags with the g / i / m / s buttons, or type flag letters directly into the small flags box next to the pattern (only
g,i,m,s,u, anddare accepted β anything else is stripped). - Paste or type your sample text into the Test String textarea below.
- Read the match count badge β it turns green when at least one match is found and red when the pattern is valid but nothing matches.
- Scan the highlighted preview: each match is wrapped in a colored
<mark>, cycling through five colors so adjacent matches are visually distinct. - Open the Match Details list to see each match's exact substring, its starting index in the string, and every capture group value β named groups show their name (e.g.
year:), unnamed groups show their position ($1:,$2:). - Click any of the four quick-example buttons (Email, URL slug, Named groups, HTML tag) to load a working pattern and test string if you want a starting point.
The Underlying Mechanism: How JavaScript Regex Matching Works
A regular expression is compiled into a state machine that walks through your input string character by character, trying to satisfy the pattern from each starting position. Literal characters must match exactly; character classes like [a-z0-9] match any one character from a set; quantifiers (*, +, ?, {n,m}) control how many times the preceding token may repeat; and parentheses ( ) create capture groups that record whatever text matched inside them so you can reference it afterward.
One detail worth knowing about this specific tool: even if you don't enable the g flag, the tester silently adds it internally (flags.includes('g') ? flags : flags + 'g') so it can walk through the string and collect every match rather than stopping at the first one. This means the match count and highlighting you see always reflect global-style scanning, even when the flag chip for g is off β the flag chip only controls what's added to the pattern you'd copy out for use in your own code.
Flags change the matching behavior itself, not just how many matches are returned. i makes the whole pattern case-insensitive. m changes ^ and $ from "start/end of the whole string" to "start/end of each line" β without it, an anchor like ^Error only matches if the string itself begins with "Error", not each line inside a multi-line log paste. s (dotAll) makes . match newline characters too, which it otherwise skips.
Worked Example: Extracting Email Addresses
Load the built-in Email example: pattern [a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,} with the g flag, against the test string "Contact us at hello@nimbica.com or support@example.org for help."
The tool returns 2 matches. Match #1 is hello@nimbica.com, starting at character index 14 (right after "Contact us at "). Match #2 is support@example.org, starting at index 35. Neither match has capture groups, because the pattern has no parentheses β it's a single flat expression, so the Match Details panel shows just the full matched text and its index for each.
Now switch to the Named groups example: pattern (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}) against "Published: 2025-08-11. Updated: 2025-09-01." This time each of the two matches (2025-08-11 and 2025-09-01) carries three named capture groups β year, month, day β and the Match Details panel labels each captured value by name instead of by position, which is exactly how you'd destructure them from match.groups in real code.
Practical Use Cases
- Debugging .htaccess rewrite rules: Test the pattern portion of an Apache
RewriteRuleagainst sample request paths before deploying it to a live server. - Validating PHP preg_match() patterns: JavaScript and PCRE (PHP's regex engine) share nearly identical syntax for common cases, so you can prototype a
preg_replace()pattern here before pasting it into a plugin. - Extracting slugs during content migrations: Pull clean URL slugs out of a list of legacy post URLs using a pattern like the URL slug example, to build a redirect map.
- Parsing log files: Isolate IP addresses, timestamps, or status codes from pasted server access logs to spot patterns manually.
- Validating shortcode or template attributes: Confirm that user-supplied attribute strings (like coordinates, hex colors, or IDs) match the format your code expects before you ship a stricter validator.
- Search-and-replace scripting: Work out the exact capture-group structure you'll need for a WP-CLI
search-replacecommand or a custom migration script.
Common Mistakes & Limitations
- Forgetting to escape literal characters: An unescaped
.matches any character, not just a period β a domain pattern without\.will still "work" on valid input but silently accept typos too. - Assuming ^ and $ match every line: Without the
mflag, anchors only apply to the very start and end of the whole test string, not each line in a multi-line paste. - Greedy quantifiers over-matching:
<.*>against multiple HTML tags will greedily span from the first<to the last>in the entire string. Use<.*?>(lazy) or a negated character class<[^>]*>instead, as the built-in HTML tag example does. - Catastrophic backtracking: Nested quantifiers such as
(a+)+btested against a long string with no trailing "b" can force exponential backtracking and freeze the browser tab. This tool's 500-match cap limits how many results it collects, but it cannot interrupt an engine that's already stuck backtracking inside a singleexec()call β test pathological patterns against short strings first. - This tool tests the JavaScript flavor only: PHP (PCRE), Python (
re), and POSIX regex have syntax differences β named groups, lookbehind support, and possessive quantifiers in particular vary between engines, so a pattern that works here may need small adjustments elsewhere.
Frequently Asked Questions
What flavour of regex does this tool use?
This tester uses JavaScript's built-in RegExp engine via the browser. It supports all ECMAScript regex features: character classes, quantifiers, groups, lookaheads/lookbehinds, named capture groups, and the flags g, i, m, s, u, d.
What is the difference between .match() and .exec()?
String.match() with the g flag returns an array of all matched substrings. RegExp.exec() returns one match at a time including capture groups and index, and must be called repeatedly for global matches. This tester effectively uses exec() to show group details per match.
What are capture groups?
Parentheses ( ) in a regex create a capture group that records the matched substring independently. Named capture groups (?<name>β¦) let you reference matched text by a descriptive name instead of a number.
Common WordPress regex use cases?
Regex is useful in WordPress for: rewrite rules in .htaccess, preg_match/preg_replace in PHP plugins, extracting URL slugs, validating shortcode attributes, parsing log files, and writing search-and-replace scripts for content migrations.
What is the difference between a greedy and a lazy quantifier?
Quantifiers like * and + are greedy by default β they consume as many characters as possible before backtracking to satisfy the rest of the pattern. Adding a ? after a quantifier (*?, +?) makes it lazy, matching as few characters as possible. For example, <b>.*</b> against "<b>one</b><b>two</b>" greedily matches the whole string, while <b>.*?</b> matches only "one" in the first pair.
Why does my pattern match nothing even though it looks correct?
The most common cause is an unescaped special character. Characters like . ( ) [ ] { } + * ? ^ $ | \ have special meaning in regex. To match a literal period in a domain name, for example, you need \. instead of a bare . β otherwise the dot matches any character, which usually still "works" but silently hides typos.
Does this tester support lookaheads and lookbehinds?
Yes. JavaScript's RegExp engine supports positive lookahead (?=...), negative lookahead (?!...), positive lookbehind (?<=...), and negative lookbehind (?<!...). These let you assert that a pattern is followed by or preceded by something without including that text in the match itself.
What is catastrophic backtracking and can it freeze this tool?
Catastrophic backtracking happens when nested quantifiers like (a+)+ force the regex engine to try an exponential number of combinations against a non-matching input. Because this tester runs your pattern in the browser's native RegExp engine, a pathological pattern against a long adversarial string can still make the tab unresponsive β the tool's internal match-count guard limits how many matches it collects, but it cannot interrupt a single exec() call that is already backtracking.
