Q133: Regular Expressions and Pattern Safety
What Interviewers Want To Evaluate
This question checks whether you can use regular expressions responsibly. Interviewers want literals, flags, capture groups, named groups, lookarounds, global state, validation limits, escaping user input, and ReDoS risk from catastrophic backtracking.
Senior answers should know when regex is useful and when a parser is safer.
Short Interview Answer
A regular expression matches text patterns. JavaScript supports regex literals, constructor-created regexes, flags such as g, i, m, s, u, and y, capture groups, named groups, and lookarounds. Regex is useful for simple pattern matching, extraction, and validation, but complex formats should often use parsers. Be careful with user-controlled patterns, escaping, global regex state, and catastrophic backtracking that can cause performance or security issues.
Detailed Interview Answer
Regex can be written as a literal:
const emailLike = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
Or created dynamically:
const pattern = new RegExp(input, "i");
Dynamic regexes require careful escaping if input is meant to be literal text.
Common Flags
Important flags include:
g: global matching
i: case-insensitive
m: multiline anchors
s: dot matches newlines
u: unicode mode
y: sticky matching
The right flag changes matching behavior significantly.
test and exec
const pattern = /error/i;
pattern.test("Server Error"); // true
exec returns match details.
const match = /user:(\d+)/.exec("user:42");
match[1]; // "42"
Capture Groups
Capture groups extract parts of a match.
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec("2026-07-25");
Named capture groups are clearer.
const pattern = /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/;
const match = pattern.exec("2026-07-25");
match.groups.year;
Lookarounds
Lookarounds assert context without consuming characters.
const pattern = /(?<=#)\w+/;
Lookarounds are expressive but can reduce readability for teams unfamiliar with them.
Global Regex State
Regexes with g or y maintain lastIndex.
const pattern = /a/g;
pattern.test("a"); // true
pattern.test("a"); // false sometimes surprising
This surprises people when the same global regex instance is reused for repeated tests.
For simple existence checks, avoid g.
Escaping User Input
If user input should be searched literally, escape regex metacharacters.
function escapeRegex(value) {
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
Then build the regex:
const pattern = new RegExp(escapeRegex(query), "i");
Without escaping, user input can change the pattern.
Validation Limits
Regex can validate simple shapes, but it should not replace domain validation.
Email validation is the classic example. A simple regex may be enough for UI feedback, but the real validation is whether the email can receive messages.
Use regex for reasonable pre-checks, not universal truth.
ReDoS Risk
Regular expression denial of service happens when a pattern causes catastrophic backtracking on certain inputs.
Risky patterns often involve nested quantifiers.
/^(a+)+$/
Against a long near-match string, this can take far too long.
Avoiding ReDoS
Practical defenses:
avoid nested ambiguous quantifiers
limit input length
use tested libraries for complex patterns
prefer parsers for structured languages
do not run untrusted regex patterns
benchmark suspicious patterns
This matters on both frontend and backend.
Regex vs Parser
Use regex for:
simple validation
token extraction
basic text search
format detection
Use a parser for:
HTML
JSON
programming languages
deeply nested formats
complex CSV
business-critical grammars
Common Mistakes
A common mistake is parsing HTML with regex.
Another mistake is using a global regex with test repeatedly and being confused by lastIndex.
Another mistake is accepting arbitrary regex input from users without limits.
Senior Trade-Offs
Regex is compact but can become unreadable quickly.
Prefer named constants, comments around complex expressions, tests with edge cases, and simpler multi-step code when the pattern becomes too dense.
Code or Design Example
const isoDatePattern = /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/;
function parseIsoDate(value) {
const match = isoDatePattern.exec(value);
if (!match) {
return null;
}
return {
year: Number(match.groups.year),
month: Number(match.groups.month),
day: Number(match.groups.day),
};
}
The regex checks shape; further date validity still needs calendar validation.
Debugging Workflow
When regex behavior is wrong:
check flags
check anchors
check greedy vs lazy quantifiers
check capture group numbering
check global lastIndex state
escape dynamic input
test long malicious inputs
consider a parser
Interview Framing
Explain regex use cases, name important flags, then discuss safety: escaping, global state, and ReDoS.
Revision Notes
Regex is powerful for pattern matching, but complex or untrusted patterns need careful safety and performance review.
Key Takeaways
The senior skill is knowing where regex is the right tool and where it becomes hidden risk.
Follow-Up Questions
- What is a regex literal?
- What does the global flag do?
- Why can
testwithgsurprise people? - What are named capture groups?
- What is a lookaround?
- Why escape user input?
- What is ReDoS?
- Why are nested quantifiers risky?
- When should you use a parser?
- How would you test a regex?
How I Would Answer This In A Real Interview
I would explain regex as pattern matching, show flags and capture groups, then focus on production safety: escape dynamic input, avoid global state surprises, test edge cases, limit input, and avoid regex for complex parsable formats.