Regex Tester
Test and debug regular expressions with real-time matching and highlighting.
Match Results
0 matchesNo matches found.
Test and debug regular expressions with real-time matching and highlighting.
No matches found.
Pattern and test text
\b(\w+)\s+\1\b
This is is a testMatched text
is isTest representative valid and invalid inputs before relying on a regular expression in production.
The Regex Tester lets you write a pattern, paste sample text, and see exactly what matches — highlighted in place, with capture groups listed — before the expression ever reaches production code. Matches update in real time as you type, so you can iterate on the pattern instead of guessing and re-running your application. It is built for developers writing validation rules, analysts extracting fields from logs, and anyone who needs to confirm what \b\w+@\w+\.\w+\b actually does.
Example 1 — a quick email sanity check. Pattern ^[^\s@]+@[^\s@]+\.[^\s@]+$ against ada@example.com matches; against ada@example it does not, because the final \.[^\s@]+ requires a dot and at least one more character. Testing with both a passing and a failing sample in the same panel shows exactly what the pattern accepts and rejects.
Example 2 — extracting URLs from a log. Run https?://[^\s"'<>]+ over a log line and each URL is highlighted in turn. The negated class [^\s"'<>]+ stops at the first whitespace or quote, avoiding the classic greedy over-match that swallows the rest of the line.
Example 3 — debugging a capture group. For a phone pattern ^\+?(\d{1,3})[-.\s]?(\d{3})[-.\s]?(\d{4})$, the group panel shows group 1 as the country code and groups 2 and 3 as the local parts. If a group comes back empty, the surrounding optional elements are usually the cause — visible immediately in the listing.
A match is the substring the engine accepted. Parentheses create capture groups: each pair records the part of the match it wrapped, numbered left to right by opening parenthesis. Groups let you extract pieces rather than just test for presence — the area code from a phone number, the key from a log line, the path from a URL.
Two refinements matter in practice. Named groups, written (?<year>\d{4}), appear under their name instead of a number, which makes longer patterns far more readable. Non-capturing groups, (?:...), group alternatives for quantifiers without adding to the numbered list; use them when (cat|dog)+ is really about the repetition, not the capture.
Alternation and anchors round out the toolkit: | chooses between options, ^ and $ pin a match to line boundaries (with the multiline flag), and \b marks a word boundary so a pattern does not match inside a longer token.
A and a as equivalent.^ and $ match the start and end of each line rather than the whole string.. to match line breaks, which it otherwise refuses to do.".*" matches from the first quote to the last quote in the text. Use ".*?" for the shortest match.\.; [.] also works and is easier to read in character classes. The same applies to +, *, ?, (, ), [, ], and {.(a+)+ can freeze the engine on near-matching input. Replace them with negated classes or anchor the pattern more tightly.^/$ without the multiline flag. They match only the start and end of the whole string, which silently breaks line-by-line validation.g flag carries a lastIndex between calls; reusing the same object can skip matches. Reset it, or create a fresh regex per test.. matches a single UTF-16 code unit unless the u flag is set, so an emoji can be split in half. Enable u for text that may contain non-BMP characters.JavaScript (ECMAScript) regular expressions, evaluated by the browser's own engine. That is the flavor you get in Node.js, Chrome, and every front-end framework, so a pattern verified here behaves identically in your application code — unlike PCRE-only features such as recursion or possessive quantifiers, which JavaScript does not support.
Almost always greediness. Quantifiers like * and + are greedy by default and consume as much as possible before the engine backtracks. Add a question mark to make them lazy (.*?) so the match stops at the nearest terminator instead of the farthest one. A negated class such as [^>]* is often a faster, clearer alternative.
Every match is highlighted in the test text. For each match, the panel lists the captured groups in order: group 1, group 2, and so on, with unnamed groups shown by number. Named groups written as (?<name>...) appear under their name. Non-capturing groups (?:...) are matched but not listed, which is useful when you only need the grouping.
g finds every match instead of stopping at the first; i ignores case; m makes ^ and $ match at line boundaries rather than only the start and end of the whole text; s lets the dot match newlines. u enables Unicode-aware matching, and it is worth turning on whenever your text may contain emoji or non-Latin scripts.
Yes — catastrophic backtracking. Patterns with nested quantifiers such as (a+)+ or (.*)* can take exponential time on inputs that almost match. If the tester becomes unresponsive, reload the page and simplify the pattern, usually by replacing a nested quantifier with a negated character class.
No. The pattern and the text are evaluated entirely in your browser with JavaScript. Nothing is transmitted, so it is safe to paste production logs, API responses, or any data you would not send to a third-party service.
Reviewed by the HandyTools Hub team · Last updated