Search

Jump to a tool or a page

Regular expressions,
tested as you type

Write a pattern, paste some text, and watch every match highlight instantly with its capture groups broken out. Free, no sign-up required.

//g
Test string
Highlighted0 matches
Matches are highlighted here as you type

Features

Everything you need to build and debug a pattern.

Highlights as you type

Every match is marked in the test string immediately, so you can see the effect of each character you add to the pattern.

Groups broken out

Numbered and named capture groups are listed per match, with the index and length of the match itself.

Replacement preview

Try a replacement string with $1 and $<name> references and see the rewritten text before you use it in code.

Runs in your browser

Patterns and test data never leave your machine, which matters when the sample text is real data.

How to test a regular expression

Three steps, and everything updates as you type.

1

Write the pattern

Type between the slashes. An incomplete pattern shows the engine error rather than clearing the result, so you can build it up gradually.

2

Set the flags

Toggle global, ignore case, multiline, and the rest. Each flag button explains what it does on hover.

3

Paste the test string

Matches highlight instantly. Open the match details below to inspect capture groups and positions.

When you need this

Where testing a pattern first saves the most time.

Building a validation rule

Test a pattern against the inputs you expect and the ones you do not, before it reaches a form or a schema.

Writing a log filter

Paste real log lines and refine a pattern until it captures exactly the requests or errors you are looking for.

Bulk find and replace

Check a replacement with capture group references here first, rather than discovering the mistake across a whole codebase.

Understanding an inherited pattern

Paste a regex someone else wrote, feed it sample text, and see what it actually matches rather than what it appears to.

Regular expressions in practice

The behaviours behind most surprising patterns: greedy quantifiers, missing anchors, the nested repetition that can hang a server, and the cases where a regular expression is the wrong tool entirely.

Greedy and lazy quantifiers

By default quantifiers are greedy: they consume as much as possible and then give characters back only if the rest of the pattern fails. This is the single most common source of a pattern that matches far more than intended.

Adding a question mark after a quantifier makes it lazy, taking as little as possible and expanding only when needed.

text:    <b>bold</b> and <i>italic</i>

<.+>     greedy →  <b>bold</b> and <i>italic</i>
<.+?>    lazy   →  <b>
[^>]+    better →  <b>

The third form is usually best. Rather than relying on laziness, describe what the content cannot contain. It states the intent directly and does not backtrack.

Anchors and word boundaries

A pattern without anchors matches anywhere in the string. That is often what you want when searching, and almost never what you want when validating.

Anchoring with ^ at the start and $ at the end forces the pattern to describe the whole input. A validation rule without them will happily accept a valid fragment buried inside garbage.

The \b word boundary is subtler: it matches the position between a word character and a non-word character, which is how you search for "cat" without also matching "concatenate".

/\d{4}/       matches "abc1234xyz"
/^\d{4}$/     matches only "1234"
/\bcat\b/     matches "the cat" but not "concatenate"

Catastrophic backtracking

Some patterns take exponential time on input that does not match. The classic shape is a repeated group that itself contains a quantifier, such as (a+)+, where the engine has an enormous number of ways to divide the same text between the two quantifiers and tries all of them before giving up.

On a short string this is invisible. On a slightly longer one it can hang a thread for minutes, which is why this class of bug has taken down production services. It is known as ReDoS when the input comes from a user.

The fix is almost always to make the inner pattern more specific so that only one division of the text is possible.

(a+)+$        catastrophic on "aaaaaaaaaaaaaaaaaaaaX"
(\w+\s?)+$    same shape, same problem
a+$           linear, does the same job

If a pattern is slow, look for nested quantifiers and alternations that can match the same text in more than one way. That ambiguity is what the engine is exploring.

When not to use a regular expression

Regular expressions describe regular languages, and several things people reach for them for are not regular. Nested structures are the clearest example: HTML, JSON, and source code all allow arbitrary nesting, which no regular expression can track.

Email addresses are the other classic. The pattern that fully implements the specification is thousands of characters long and still does not tell you whether the address exists. Checking for an @ with something on each side, then sending a confirmation message, is both simpler and more accurate.

Dates are a third. A pattern can confirm the shape 2026-02-30 but not that it is a real day. Parse it with a date library and check whether the result is valid.

Regular expressions are excellent at recognising flat patterns in text. When the thing you are matching has structure, use a parser and keep the regex for the leaves.

Unicode and the u flag

Without the u flag, JavaScript regular expressions operate on UTF-16 code units rather than characters. A single emoji is two code units, so a dot matches only half of it and a character class can split it in a way that produces invalid text.

The u flag makes the pattern operate on code points, which is what you want whenever the input might contain anything outside the basic multilingual plane. It also enables \p{...} property escapes, so you can match "any letter in any script" rather than enumerating ranges.

Note that \w, \d, and \b remain ASCII-only even with the u flag. \w means [A-Za-z0-9_] and always has, so a pattern using it will not match accented letters or non-Latin scripts.

/^.$/u.test("😀")        → true
/^.$/.test("😀")         → false (two code units)
/\p{Letter}+/u           → matches é, ß, 日本語

Common questions

Which regex flavour does this use?

JavaScript regular expressions, as implemented by your browser. The syntax is close to PCRE for everyday patterns, but there are differences: JavaScript has no lookbehind in older engines, no possessive quantifiers, and no recursion. Patterns written for Python, PHP, or Java may need small adjustments.

What is the difference between a capture group and a non-capturing group?

Parentheses group part of a pattern and, by default, capture what matched so you can reference it later as $1, $2, and so on. Writing (?:...) groups without capturing, which keeps the numbering clean and is slightly faster when you only needed the grouping.

Why does my pattern only find the first match?

Without the g flag a regular expression stops at the first match. Turn on global to find every occurrence. This tool lists all matches regardless so you can see what a global search would return, but the flag still controls what your own code would do.

What are named capture groups?

Written as (?<name>...), they let you refer to a captured value by name rather than by position. It makes patterns far more readable and means adding a group at the front does not renumber everything after it. Reference them as $<name> in a replacement.

Is my test data sent to a server?

No. The pattern is compiled and run by your own browser, and nothing you type is transmitted or stored. That makes it safe to test against real log lines or customer records.

Related tools

Other free tools that tend to come up in the same work.