Crunchify.net

Regex Tester

Test and debug regular expressions in real time.

Pattern
/ /g
Test String
Substitution
Tests

Strings this pattern should, or should not, match. They travel in the share link.

No tests yet.

Regular expressions (regex) are patterns used to find, match, and extract text. This tester uses the browser's built-in JavaScript regex engine — the same one used in String.prototype.match(), replace(), and matchAll().

Flags change how matching works: g finds all matches (without it, only the first is returned); i ignores case; m makes ^ and $ match line boundaries instead of the whole string; s (dotAll) makes . match newlines; u enables full Unicode support; v (unicodeSets) is u plus set operations inside character classes, so the two never go together; y (sticky) makes each match start exactly where the last one ended.

Group colours: in the highlighted preview each capture group gets a colour and a small number, and the match table heads each group's column with the same colour and number, so the two can be read against each other without relying on the colour. The table gives every match and every group its position as start–end.

Capture groups let you extract parts of a match. Use () for numbered groups and (?<name>) for named groups. Non-capturing groups (?:) group without capturing, which is faster when you don't need the captured value.

Greedy vs. lazy: quantifiers like * and + are greedy by default — they match as much as possible. Adding ? makes them lazy: .*? matches as little as possible.

Catastrophic backtracking is what happens when one quantifier is nested inside another, as in (a+)+. On text that does not match, the engine tries every way of dividing the characters between the inner and outer quantifier, and the number of ways roughly doubles with each character added — so the test string does not need to be long. Thirty characters is already enough to run for hours. This tester matches in a background Web Worker and stops any pattern still running after 2 seconds, so a pattern like that costs you a warning rather than the tab.

Tests pin down what a pattern is for. Add strings it should match and strings it should not, and each one passes or fails as you edit the pattern, so a fix for one case that breaks another shows at once. With substitution on, a test can also give the result replacing should produce. Tests are saved in the share link with the pattern, so sending the link sends the cases it has to pass.

When you need more than a match list

This tester runs your pattern against JavaScript's engine and shows you what matched. When you need to know why — or you are writing a pattern for a different language — use regex101. It explains a pattern token by token, switches between PCRE2, Python, Java, .NET, Go, Rust and POSIX flavours, and adds substitution, extraction and unit tests. It needs no account. It shows an advert and runs cookieless analytics, saving a pattern uploads your test text to its server, and it has a paid tier.

Link to this tool with values filled in

Everything after the # stays in your browser — it is never sent to a server — so a link like this opens the tool ready to go without the values travelling anywhere but the address bar:

https://crunchify.net/tools/regex-tester#pattern=%5Cb%5Cw%2B%40%5Cw%2B%5C.%5Cw%2B%5Cb&text=mail%20me%20at%20joe%40example.com&flags=g

Join the settings with &, and percent-encode each value so that spaces, newlines and any #, &, = or % inside one do not break the link. Leave a setting out to accept its default. If a setting is not recognised, the page says so rather than quietly ignoring it.

  • pattern (also regex, re or expression) — text, up to 512 characters, required. The regular expression source, without delimiters or flags.
  • flags (also modifiers or opts) — text, up to 8 characters, defaults to nothing. Any of `g` `i` `m` `s` `u` `v` `y`, in any order, but not `u` with `v`. Unsupported letters are reported rather than ignored.
  • text (also input, subject or against) — text, up to 1024 characters, defaults to nothing. The text to run the pattern against.
  • replacement (also replace, substitution or with) — text, up to 512 characters. Turn on substitution with this replacement: `$1`, `$<name>`, `$&` and `$$` work as in JavaScript. Omit it to only match.

What do the regex flags mean?

g = global (find all matches, not just the first). i = case-insensitive. m = multiline (^ and $ match line boundaries). s = dotAll (. matches newlines). u = Unicode (enables full Unicode support and stricter parsing). v = unicodeSets (see below). y = sticky (see below).

What does the sticky (y) flag do?

With y, a match must start exactly at the position the search is at: the start of the text for the first match, then right where the previous match ended. So /a/gy on "aab" finds two matches but on "aba" finds only one, because the second a is not adjacent to the first. Without g, y means the pattern must match at the very start.

What is the v (unicodeSets) flag, and why does turning it on turn u off?

v is a newer edition of u. It does everything u does and adds set operations inside character classes — [\p{L}--[a-z]] is any letter except a to z, and [\w&&\d] is the characters in both — plus properties of strings such as \p{RGI_Emoji}. JavaScript rejects a pattern that has both flags, so this tester switches one off when you switch the other on.

Why does the tester stop at 500 matches?

To keep the page responsive on a very long test string. When a pattern matches more than 500 times, the match count reads 500+ and the table says it is showing the first 500.

What is the difference between .* and .*?

.* is greedy — it matches as many characters as possible. .*? is lazy — it matches as few characters as possible. Example: on "aXbXc", a.*X matches "aXbX" (greedy), while a.*?X matches "aX" (lazy).

How do I match a literal dot or parenthesis?

Escape it with a backslash: \. matches a literal dot, \( matches a literal opening parenthesis. Without escaping, . matches any character and ( starts a capture group.

What is a capture group?

Parentheses () create a capture group that extracts the matched substring. Example: (\d{4})-(\d{2})-(\d{2}) on "2024-01-15" captures group 1 = "2024", group 2 = "01", group 3 = "15". Named groups use (?<name>...) syntax.

What causes catastrophic backtracking?

A quantifier nested inside another one, like (a+)+, on text that does not match. The engine tries every way of dividing the characters between the two quantifiers before it can conclude the match failed, and the number of ways roughly doubles per character — so it is the nesting that causes it, not the length of the test string. (a+)+$ against 30 letters will run for hours. Avoid overlapping quantifiers on the same characters. This tester runs matching in a Web Worker and cancels any pattern still going after two seconds, so it warns you instead of freezing the tab.

Updated October 13, 2026