Regex questions show up constantly in technical interviews — partly because they’re easy to ask in five minutes, and partly because a good answer reveals whether you actually understand pattern matching or just copy-paste from Stack Overflow. Here are six that come up again and again, with the kind of answer that shows real understanding.
1. Write a regex to validate an email address
The honest answer starts with a caveat: the real email spec (RFC 5322) is famously complicated, and no interviewer expects you to reproduce it from memory. What they want is a pattern that’s reasonable for practical validation, plus awareness that it isn’t bulletproof.
const emailPattern = /^[\w.+-]+@[\w-]+(\.[\w-]+)+$/;
This says: one or more “word” characters, dots, plus signs, or hyphens (the local part), then @, then a domain made of one or more label.label segments.
Notice missing@tld and @nodomain.com correctly fail — the first has no dot in the domain, the second has an empty local part. The strongest answer here isn’t “I memorized the perfect regex” — it’s explaining why full RFC 5322 validation is a bad goal in the first place, and that sending a confirmation email is a better real-world check than a perfect pattern.
2. How do you match balanced parentheses — and why can’t plain regex do this fully?
This question tests whether you understand what regex fundamentally is: a description of a regular language, recognized by a finite automaton with no memory of how deep it is nested. Matching balanced parentheses — (a(b)c), ((())), arbitrarily deep — requires counting, and a finite automaton has a fixed, finite number of states, so it can’t count to an unbounded depth. That’s a job for a context-free grammar and a stack-based parser, not a regular expression.
You can match one level of non-nested parentheses easily enough:
Look at what happens on (a(b)c): the pattern can’t grab the whole balanced expression — it only finds the innermost (b), because [^()]* refuses to cross another ( or ). That’s the limitation in action, not a bug in the demo.
Tip
Some engines (PCRE, .NET) add recursive patterns like (?R) or balancing groups specifically to work around this limitation — which is itself evidence that it’s a real limitation of standard regex, not just a skill issue. JavaScript’s built-in engine doesn’t support recursion, so in JS you’d reach for an actual parser instead.
3. What’s the difference between greedy and lazy quantifiers?
A greedy quantifier (*, +, {n,}) matches as much as it possibly can, only giving characters back if that’s the only way the rest of the pattern can succeed. A lazy quantifier (*?, +?, {n,}?) matches as little as possible, only taking more if it has to.
The classic example is matching HTML-like tags:
With the lazy <.+?>, you get four clean matches: <b>, </b>, <i>, <i>. Change the pattern to the greedy <.+> against the same text and it collapses into a single match spanning from the very first < to the very last > — because .+ grabs everything, then gives back characters one at a time only until it finds a > to satisfy the pattern, which turns out to be the last one in the string.
4. How would you extract all numbers from a string?
Use \d+ with the global flag, and decide up front whether you care about decimals and negative signs — that decision changes the pattern.
-?\d+(\.\d+)? says: an optional leading minus sign, one or more digits, then an optional decimal point followed by more digits. It correctly pulls out -3, 4.5, 100, and 0.75 as four separate numbers, treating the decimal point as part of the number rather than a separator.
5. Explain capturing vs non-capturing groups
Both (...) and (?:...) group a subpattern so you can apply a quantifier or alternation to the whole thing. The difference is what happens afterward: (...) is a capturing group — the engine remembers what it matched and exposes it as a numbered (or named) submatch you can reference later, in a replacement string or a backreference. (?:...) is a non-capturing group — same grouping behavior, but nothing gets remembered.
Run the demo and check the match details — you’ll see it reports 3 capture groups (year, month, day) because every set of parentheses here captures. If you rewrote the first group as (?:\d{4}), that group would still restrict what matches, but it would drop out of the capture count entirely. The practical rule of thumb: capture what you need to extract or reuse; make everything else non-capturing to keep your match results clean and slightly faster to produce.
6. What does catastrophic backtracking mean?
It’s what happens when a regex engine’s backtracking search explodes combinatorially on a failing match. The textbook trigger is a quantifier nested inside another quantifier over the same characters, like (a+)+b:
// Fine — matches quickly
/(a+)+b/.test("aaaaaaaaaaaaaaaaaaaab");
// Catastrophic — can hang for seconds, minutes, or effectively forever
/(a+)+b/.test("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!");
For a run of n characters a, there are exponentially many ways to split them between the inner a+ and the outer (...)+ . When the string is followed by something that doesn’t match (like ! instead of b), the engine has to try every single split before giving up — and that count doubles roughly every time you add one more a.
Watch out
This isn’t a hypothetical: catastrophic backtracking has caused real production outages (a well-known 2016 Cloudflare incident was triggered by exactly this pattern shape). You’ll see how to spot and avoid it in the Performance lesson earlier in this course — the short version is to avoid nested quantifiers over overlapping character sets, and prefer atomic groups or possessive quantifiers where your engine supports them.
Try it yourself
Take the email pattern from question 1 and test it against "a@b.c" and "a..b@example.com". Do either surprise you?
What should happen
"a@b.c" matches — a single-letter local part, single-letter domain label, and a one-character TLD are all technically allowed by [\w.+-]+, [\w-]+, and (\.[\w-]+)+, even though a real TLD is never just one letter. "a..b@example.com" also matches, because [\w.+-]+ happily accepts consecutive dots in the local part, which real mail servers usually reject. Both are reminders that a “reasonable” validation regex is a heuristic, not a guarantee — exactly the nuance interviewers are listening for.
What’s next
You’ve now got solid answers for the questions interviewers actually ask. The next lesson turns things around: instead of answering questions about regex, you’ll write regex to solve graded challenges, from Easy warm-ups to Expert-level puzzles.