Every developer has a regex story. Mine is the signup form that quietly rejected anyone whose password contained a $ — for a month — because the validator I'd copied assumed "letters, numbers, and a few symbols" meant only the five symbols I'd remembered to list. No error ever fired; the form just kept saying "password too weak." The bug wasn't that regex is hard. It's that regex looks right while being wrong, and you can't tell the difference until you watch it actually run against real input.
That's exactly what an online regex tester is for: a place where you type a pattern, paste some text, and see every match highlighted the instant you type — so a pattern that "should work" and one that actually works stop being two different things.
Why regex is hard to get right
A regex is a tiny program written in a punctuation-only language, and like any program, it can compile but still be wrong. Two properties make it uniquely easy to get wrong:
- It matches what you wrote, not what you meant.
\d+matches any run of digits — including a substring in the middle ofabc123def. If you wanted a number on its own, you need anchors to say "the whole thing, nothing else." - It's silent about near-misses. A pattern that fails to match, or matches too broadly, usually produces no error — just the wrong result. There's no compiler warning for "this will also match the wrong thing."
The fix for both is the same: stop running regexes blind. Feed them sample input — the good cases and the edge cases — and watch exactly what they match before they ship.
The building blocks of a regex
Most patterns are assembled from a handful of pieces. If you can read these, you can read almost any regex you'll meet in the wild:
- Literals —
a,b,0,_match themselves, exactly. - Character classes —
[abc]matches any one of those;[0-9]any digit;[^abc]anything except those. Shorthand:\ddigit,\wword character,\swhitespace. - Quantifiers —
?(zero or one),*(zero or more),+(one or more),{3}(exactly three),{2,5}(two to five). They apply to whatever comes just before them. - Anchors —
^matches the start of the text,$the end. Together they force a match of the whole string rather than a part of it. - Groups and alternation —
(...)groups (and captures) a sub-pattern;a|bmeans "a or b".(?:...)groups without capturing. - Escaping — a backslash before a special character makes it literal:
\.matches a period, not "any character".
The single most important habit is anchoring. \d{3} matches "123" inside "x12345y", but ^\d{3}$ matches only a string that is exactly three digits. When you're validating an input field, you almost always want the anchored version.
A real example
Suppose you've pasted a chunk of an access log into a text box and you want to pull out every email address in it. A common first attempt looks like this:
[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}
Read it piece by piece: [a-zA-Z0-9._%+-]+ is one or more characters allowed in an email local part, then a literal @, then [a-zA-Z0-9.-]+ for the domain, then \. for the dot, then [a-zA-Z]{2,} for a two-or-more-letter top-level domain. Paste that into a tester with your log as the test string, and every address lights up as a match while the surrounding text stays dim — so you can see at a glance whether it's catching the right things.
Now try the same idea but anchored, to validate a single address rather than find one inside text:
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
The only change is ^ and $ at the ends — but now it matches name@example.com and rejects not an email name@example.com, because the whole string has to be one address. That one character at each end is the difference between "finds emails in text" and "checks that a field is an email." This is why testing against real sample input matters: the two patterns are near-identical to read but opposite in behavior.
Greedy vs. lazy matching
The classic regex bug — the one that makes a pattern match far more than you expected — is greediness. By default, quantifiers are greedy: they match as much text as they possibly can. Consider extracting the text inside a pair of parentheses:
\(.*\)
Against a (first) and (second), you might expect two matches — (first) and (second). Instead, .* greedily swallows everything up to the last ), so the single match is (first) and (second). The fix is to make the quantifier lazy by adding ? after it:
\(.*?\)
Now .*? matches as little as possible, so it stops at the first ) and you get two matches, as intended. The rule of thumb: when the character your quantifier is matching also appears elsewhere in the text you're searching, reach for the lazy form *? or +? first. A tester makes this instantly obvious — you type both versions and watch the highlight shrink from "everything" back to "just the two groups."
Common patterns to copy
You rarely need to write a pattern from scratch. Most everyday validation is solved, so start from a known-good pattern and adapt it:
Email^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
Date (YYYY-MM-DD)^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
IPv4 address^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$
Username (3-16 letters, digits, underscore)^[a-zA-Z0-9_]{3,16}$
Strong password (8+ chars, mixed cases, digit, symbol)^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$
Hex color^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$
UUID^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$
The Regex Tester bundles these and more in a built-in "Common Patterns" tab — email, phone number, URL, credit card, MAC address, and a dozen others — each one click-to-copy, so you can grab a pattern and start adapting instead of re-deriving it from scratch.
Why it runs entirely in your browser
The text you're matching against is usually the last thing you'd want to paste into a third-party server: log lines with user data, config with secrets, a CSV of customer records. A good regex tester matches everything locally — the pattern is compiled and run by your browser, and neither your regex nor your text ever leaves your device, gets uploaded, or gets logged. Paste real data with confidence; it stays where it belongs.
Frequently asked questions
What is a regular expression?
A regular expression (regex) is a compact pattern that describes a set of strings. You use it to search, match, validate, or extract text — for example, to check whether an input is a valid email address, or to pull every date out of a log file.
How do I test a regex online?
Open a regex tester, type your pattern into the pattern field, and paste the text you want to match against. The matches are highlighted in real time, so you can refine the pattern until it matches exactly what you intend.
What do the g and i regex flags mean?
The g flag makes the pattern global, so it finds every match instead of stopping at the first one. The i flag makes matching case-insensitive, so it treats uppercase and lowercase letters as the same.
Why isn't my regex matching anything?
The most common causes are unescaped special characters, missing anchors, or a greedy quantifier that over-matches. Try escaping reserved characters like . * + ? | and test one small piece of the pattern at a time.
What is the difference between greedy and lazy quantifiers?
A greedy quantifier matches as much text as possible, while a lazy quantifier matches as little as possible. Adding a question mark after a quantifier, as in *? or +?, makes it lazy — which is usually what you want when the surrounding text also contains the character you're matching.
Is my data safe when I use an online regex tester?
With a client-side regex tester, yes. The matching runs entirely in your browser, so your pattern and your text never leave your device and are never uploaded or logged. That matters when the text you're matching contains logs, config, or customer data.
Matching patterns is only half the job — once you've pulled the data, you usually need to shape it. If your match result is JSON, see How to Format and Validate JSON; if you're validating a password field, pair the strong-password pattern above with How to Create a Strong Password (That You Can Actually Remember).
Ready to test your regex?
Open the free, in-browser Regex Tester, type your pattern and paste your text, and watch every match light up in real time — nothing uploaded.
Try the Regex Tester