🔍 Regex Tester

Test regular expressions against text in real-time — highlights every match, shows capture groups, index positions, and named groups.

⚠️
Invalid Regular Expression
Fix the pattern to see matches
No matches found
(g off)
·
Test Text
🔆 Match Preview no matches — showing plain text
Match Details
🔬

Enter a regex pattern above to see match details here.

⚠️

Fix the pattern error to see matches.

📝

Paste test text on the left.

🔎

No matches found.

Try toggling the i flag for case-insensitive matching, or the m flag for multiline.

Showing first of matches. Remove the g flag or refine your pattern to reduce results.

Quick Presets

Regex Quick Reference

PatternDescription
Anchors
^Start of string (or line with m)
$End of string (or line with m)
\bWord boundary
\BNon-word boundary
Character Classes
.Any char except \n (or all with s)
\d / \DDigit / non-digit
\w / \WWord char [A-Za-z0-9_] / not
\s / \SWhitespace / non-whitespace
[abc]Character class — a, b, or c
[^abc]Negated class — not a, b, or c
[a-z]Range — lowercase letter
PatternDescription
Quantifiers
*0 or more (greedy)
+1 or more (greedy)
?0 or 1 (optional)
{n}Exactly n times
{n,m}Between n and m times
*? +?Non-greedy (lazy) variants
Groups & Lookarounds
(x)Capturing group
(?:x)Non-capturing group
(?<n>x)Named capturing group
(?=x)Positive lookahead
(?!x)Negative lookahead
(?<=x)Positive lookbehind
(?<!x)Negative lookbehind
x|yAlternation — x or y

How matching and the flags are applied

The pattern you type is compiled into a JavaScript regular expression with whichever flags are switched on. If compilation fails, the error from the engine is displayed directly, so a message about an unterminated character class or nothing to repeat points straight at the offending part of the pattern.

With the global flag on, the tester iterates through the test text collecting every non-overlapping match. With it off, only the first match is returned, which is the behaviour of a single exec call. For each match it records the matched text, the index at which it starts, the index at which it ends, and its length in characters. Zero-length matches are labelled explicitly, since an empty result is otherwise indistinguishable from no match.

Capture groups are read from the match result in order and shown as $1, $2 and so on. A group that participated but captured nothing shows an empty value, while one that did not participate is marked with an empty-set symbol. Named groups are listed separately.

The other flags behave as in JavaScript: i ignores case, m makes the anchors match at every line boundary, s lets the dot match newlines, and u enables unicode handling.

Worked example: extracting ISO dates from a line of text

Set the test text to: Invoices 2024-03-15 and 2025-11-02 are due. Set the pattern to the word-boundary date form, a boundary followed by four digits, a hyphen, two digits, a hyphen, two digits and a closing boundary. Leave the global flag on.

The tester reports two matches. The first is 2024-03-15. Counting from zero, the word Invoices occupies indices 0 to 7 and the space is index 8, so the match starts at index 9, ends at index 19 and has a length of 10. The second match is 2025-11-02. The five characters of space, a, n, d and space occupy indices 19 to 23, so it starts at index 24, ends at 34 and is also 10 characters long.

Now wrap each component in parentheses to create three capture groups. The first match still spans indices 9 to 19, but now reports $1 as 2024, $2 as 03 and $3 as 15. Rename them as named groups and the same values appear labelled year, month and day instead.

Turn the global flag off and only the first match is returned, at index 9. The count drops from two to one while the pattern itself is unchanged.

Reading the output and avoiding common regex mistakes

Indices are zero-based and the end index is exclusive, matching JavaScript convention, so a match from index 9 to index 19 covers ten characters. That detail is the one most often misread when translating a result into slice arguments elsewhere.

A very common surprise is a pattern that matches far more than intended, which nearly always comes from a greedy quantifier. A dot-star between two delimiters runs to the last occurrence in the text rather than the nearest one; adding a question mark to make it lazy fixes it. Another is forgetting that the dot does not cross newlines unless the s flag is on, which silently breaks patterns tested on single-line samples and then used on real multi-line input.

If a pattern produces enormous numbers of matches, the display is capped and the tester notes how many are being shown out of the total, so a large count is not a rendering bug.

Two limits are worth knowing. This is the JavaScript engine, so syntax that works in PCRE or Python may not compile here. And regular expressions are the wrong tool for nested structures like HTML or JSON.

Frequently Asked Questions

The g flag finds all matches instead of stopping at the first. The i flag makes matching case-insensitive. The m flag makes the caret and dollar anchors match at each line break rather than only at the start and end of the text. The s flag lets the dot match newlines, and u enables full unicode support.
Almost always a greedy quantifier. Constructs like .* and .+ consume as much as possible, so a pattern between two delimiters stretches to the last delimiter in the text rather than the nearest. Add a question mark after the quantifier to make it lazy, or replace the dot with a negated character class.
It is the zero-based character position where the match begins in the test text, with the end index being the first position after the match. A match reported at index 9 with length 10 runs from index 9 up to but not including index 19, which is the same convention slice uses.
Yes. Named groups written in JavaScript syntax are listed separately by name alongside the numbered groups, so you can confirm that each name captured the value you expected. One of the built-in preset patterns demonstrates named groups if you want a working example to start from and adapt.
Often, but not always. This uses the JavaScript regex engine, and while the core syntax is shared, features differ at the edges: lookbehind support, unicode property escapes, named group syntax and recursion all vary between engines. Test anything unusual in the language you will actually deploy it in.