How to Test Regular Expressions: Patterns, Flags and Capture Groups Explained
A regular expression is a tiny pattern language for finding text: a few characters that describe “an email address,” “a US phone number,” or “every word starting with a capital letter,” and an engine that finds every match. The trouble is that a pattern that looks right can silently match the wrong things — or nothing at all — and the only cure is testing it against real sample text. Our online regex tester is built for exactly that loop: type a pattern into the pattern box, paste sample text below it, press Test Regex, and matches highlight instantly with a count and capture-group details for every hit. Nothing leaves your browser — the pattern compiles and runs with the built-in JavaScript regex engine — and you do not need slashes or delimiters around the pattern. This guide walks through the pieces of a pattern, the flags that change its behaviour, a worked email example, and the mistakes that cost developers the most time.
How to Use the Tester
1. Type the pattern. Enter it bare, without surrounding slashes: \d{3}-\d{4}, not /\d{3}-\d{4}/. 2. Paste sample text. Include both text that should match and text that should not — a tester fed only matching examples cannot reveal over-matching, which is the more expensive failure. 3. Set the flags. The flags are toggles: g for global, i for case-insensitive, m for multiline, s for dotAll, u for Unicode, and y for sticky (explained below). 4. Read the match details. Beyond the highlights, the tester lists each match with its capture groups, so you can see exactly what each parenthesised part captured before the pattern ever reaches your code. If you are short of a starting point, the Email, URL, and US Phone preset buttons drop in a working pattern for each case — a far better start than a blank box. When a pattern is meant to validate data you will later encode or store, our Base64 encoder handles the text-safe side of that pipeline, and our JSON formatting guide covers the structured data the matches usually end up in.
The Anatomy of a Pattern
Most patterns are built from five kinds of pieces. Literals match themselves: cat matches the letters c-a-t. Character classes match one character from a set: [A-Z] is any capital letter, \d is any digit, \w is a word character (letters, digits, underscore), and \s is whitespace. Quantifiers say how many: * means zero or more, + means one or more, ? means zero or one, and {3} or {2,4} give exact counts — so \d{5} is exactly five digits, which is why it will never match a four-digit number. Anchors say where: ^ is the start and $ is the end (of the text, or of each line with the m flag). Groups, in parentheses, do two jobs at once: they group pieces so a quantifier applies to all of them, and they capture what matched, so (\d{3})-(\d{4}) captures the area code as group 1 and the rest as group 2. Alternation with | gives choices: cat|dog matches either word. Everything else in regex is a variation on these five ideas, which is why a pattern that looks intimidating is usually just a long chain of them.
Flags: The Six Switches That Change Everything
Flags are the most common reason a correct-looking pattern behaves unexpectedly, so learn them as a set. The g flag (global) finds all matches instead of stopping at the first — without it, a tester shows you one match and hides the rest. The i flag makes matching case-insensitive, so “Email” matches “email”; without i, the same pattern misses half your data. The m flag (multiline) lets ^ and $ match at each line boundary instead of only at the very start and end of the whole text, which matters the moment your sample has more than one line. The s flag (dotAll) lets the dot match line breaks too, so .* can span lines. The u flag enables Unicode mode, which makes the engine handle emoji and astral-plane characters correctly instead of treating them as two half-characters. The y flag (sticky) anchors each match attempt to the engine's current position, a specialist tool for parsers rather than everyday searching. When a pattern finds nothing, check the flags first: a missing i or a stray ^ without m explains most empty results before any deeper debugging is needed.
Worked Example: Matching an Email Address
Take the pattern from the tester's own Email preset, in spirit: ([A-Za-z0-9._%+-]+)@([A-Za-z0-9.-]+\.[A-Za-z]{2,}). Read it left to right. Group 1, [A-Za-z0-9._%+-]+, is one or more characters from the username set — letters, digits, dot, underscore, percent, plus, hyphen. Then a literal @. Then group 2, the domain: [A-Za-z0-9.-]+, one or more domain characters, then an escaped dot \. (a bare dot would match anything, so it must be escaped to mean a literal dot), then [A-Za-z]{2,}, two or more letters for the top-level domain. Paste “Contact ada@example.com or bob@test.org for help” and you get two matches; the match details show group 1 as “ada” and “bob” and group 2 as “example.com” and “test.org” — exactly the pieces code would pull out as match[1] and match[2]. Paste “ada@example” and it does not match, because the top-level domain needs at least two letters after the dot. That is the pattern doing its job: a validator that accepts “ada@example” would pass bad data into your system, and the tester shows you the rejection before your users do.
Common Mistakes
Forgetting to escape literal special characters. A bare dot matches anything, a bare parenthesis breaks the pattern, and a bare plus quantifies whatever precedes it. If you mean the literal character, escape it: \., \(, \+. Anchoring too tightly or not at all. ^\d+$ requires the whole text to be digits; without anchors, the same pattern matches a digit substring inside anything. Greedy quantifiers eating too much. .* grabs as much as it can; when it swallows the closing tag you wanted, try the lazy form .*?, which grabs as little as possible. Testing only matching examples. Feed the tester near-misses too — the wrong case, the short number, the missing dot — because a pattern's failures are where its real behaviour lives. Quantifier with nothing before it. A pattern starting with * or + is invalid; the tester shows the engine's exact error plus a plain-language hint pointing at the likely culprit, so fix that spot and re-test rather than rewriting the whole pattern. Assuming one engine fits all. This tester uses the JavaScript engine, so a pattern tuned for another language's engine (lookbehind support and flag details differ) should be re-tested here before it ships in browser code.
Limits Worth Knowing
The tester runs entirely in your browser, so your sample text is never uploaded — but that also means it tests JavaScript regex semantics, not Python's or Go's. Very long texts and pathological patterns (nested quantifiers such as (a+)+) can run slowly, because backtracking grows fast; if a test hangs, simplify the pattern rather than feeding it more text. And a tester can only show you what a pattern does, not what you meant: the final check is always a human reading the match list and asking, “is that really every case I want, and only those cases?”
Frequently Asked Questions
How do I test a regular expression online?
What do the regex flags g, i, m, s, u and y do?
Why is my regex invalid, and how do I fix it?
What are capture groups in regex?
Why does my pattern find no matches?
More guides from ToolNest
How to Format JSON: Validation, Indentation and the Errors That Break Parsers
Paste, validate, pretty-print: the formatter that pinpoints the exact error, counts keys and depth, and turns a one-line blob into readable, diffable JSON.
How to Encode and Decode Base64: What It Is, What It Is Not, and When to Use It
Three bytes become four characters, output grows by about a third, and the = padding marks where the data ends — plus the one rule that matters: Base64 is not encryption.
Cron Expression Generator
Build a portable 5-field schedule with plain-language previews and the next run times — the companion tool to this batch's cron guide.