Skip to content
Browser tool Runs locally

Regex Tester

Test regular expressions against text using your browser's native JavaScript regex engine. Runs locally.

Regex
Examples:
Test text
0 chars
Results
Matches will appear here after you test a pattern.

What is a regex tester?

A regex tester lets you write a regular expression, run it against a piece of text, and see what it matches.

How to test a regular expression

  1. Enter a pattern in the Regex field.
  2. Toggle the flags you want.
  3. Paste the text to test.
  4. Click Test Regex.

What are regex flags?

  • g - Global. Find all matches.
  • i - Ignore case.
  • m - Multiline.
  • s - dotAll.
  • u - Unicode.
  • y - Sticky.
  • d - Indices.

Practical pattern examples

  • \d{3}-\d{4} - three digits, a literal hyphen, four digits (e.g. a local phone extension format). \d matches any digit, and {3} repeats the previous token exactly 3 times.
  • ^[A-Za-z0-9_]+$ - a whole string made only of letters, digits, or underscore, useful for validating a username or slug. ^ and $ pin the match to the very start and end, and + requires at least one character.
  • \s+ - one or more consecutive whitespace characters (spaces, tabs, newlines), commonly used to collapse repeated whitespace down to a single space.
  • #(\w+) - a # followed by one or more word characters, with the word part captured in group 1 so you can extract a hashtag without the leading symbol.

Greedy vs. lazy quantifiers

Quantifiers like *, +, and {n,m} are greedy by default: they match as much text as possible, then backtrack only if the rest of the pattern fails to match. Against <b>bold</b>, the pattern <.*> matches the entire string - from the first < to the very last > - because .* grabs everything it can before giving anything back. Adding a ? after a quantifier makes it lazy instead: <.*?> matches as little as possible, so it stops at the first > and matches only <b>. When a pattern matches far more than expected, a greedy quantifier is almost always the reason.

Anchors: ^ and $

^ matches the start of the input and $ matches the end - with nothing else in the pattern, they don't consume any characters, they just require a position. Without them, a pattern like \d+ matches digits anywhere inside a longer string; wrapping it as ^\d+$ requires the entire string to be nothing but digits. By default ^/$ only apply to the start/end of the whole input, not each line - enable the m flag if you need them to match at every line break in multi-line text instead.

Common escaping mistakes

  • Leaving . unescaped when a literal period is intended - . matches any character, so example.com as a pattern also matches exampleXcom. Use example\.com to require the literal dot.
  • Forgetting that (, ), [, ], {, }, |, +, and * are all structural characters - matching one literally (e.g. a price like $5.00) requires escaping the parts that aren't already plain text, such as the $ itself when it isn't meant as an anchor.
  • Forgetting that a regex written inside a JavaScript string literal needs its backslashes doubled - "\\d" in source code represents the single-backslash pattern \d. In this tool you type the pattern directly, so it's just \d with no extra escaping.

Catastrophic backtracking

Some patterns can take an exponential amount of time to fail against certain input, freezing the page or the process running them. This typically comes from nested or overlapping quantifiers, such as (a+)+$ or (a|a)*$, where the engine has many equivalent ways to split the same repeated characters and tries most of them before giving up. A short non-matching input (a few dozen characters) can trigger it just as easily as a long one. If a pattern is slow only on specific input rather than consistently, suspect catastrophic backtracking first - the fix is usually to remove the ambiguous nested repetition, not to add a longer timeout.

Testing a regex before production use

  • Test against real edge cases, not just the input you had in mind: empty strings, extra whitespace, unexpectedly long input, and any Unicode your data might contain.
  • If the pattern has nested or repeated groups, deliberately try a long, non-matching string to rule out catastrophic backtracking before it runs on live traffic.
  • Confirm which flags you actually need - an accidentally missing g silently returns only the first match, and an accidentally present i can make a case-sensitive check pass when it shouldn't.
  • Prefer anchoring with ^/$ (or \b word boundaries) over assuming a pattern won't partially match inside a larger string.

Frequently asked questions

Why did my regex match way more text than I expected?
This is almost always a greedy quantifier. A pattern like <.*> against "<b>bold</b>" matches the entire string, from the first < to the last >, because .* greedily grabs as much as possible before backtracking. Switching to <.*?> (lazy) matches only <b>, stopping at the first >.
Why does my pattern hang or freeze the page on some input?
That's catastrophic backtracking - certain patterns with nested or ambiguous repetition (e.g. (a+)+$) can force the engine to try an exponential number of ways to match before failing, so runtime blows up on specific inputs even though the pattern looks harmless on short text. Rewriting the repetition to remove the ambiguity (or adding a more specific anchor) is the fix, not just adding a timeout.
Why do I need to escape characters like . or ( in my pattern?
Characters such as . ? * + ( ) [ ] { } | ^ $ \ have special meaning in a regex. To match them literally - a literal period in a domain name, for example - escape them with a backslash: \. instead of . . Forgetting this is the single most common cause of a pattern matching more than intended.
Why doesn't ^ or $ do what I expect on multi-line text?
By default, ^ and $ match only the very start and end of the whole input string, not the start/end of each line. If you're testing line-by-line text and want ^ / $ to match at every line break, enable the m (multiline) flag.
How should I test a regex before using it in production?
Run it against real edge cases, not just the happy path: empty strings, very long strings, and the boundary cases your data actually contains (extra whitespace, unexpected Unicode, unusually long repeated characters). If the pattern has nested quantifiers, deliberately try a long, non-matching input to check for catastrophic backtracking before it ships.

Related tools