JavaScript Regular Expressions: A Complete Practical Guide
Regular expressions are one of those tools that feel intimidating at first but become indispensable once you understand them. They appear in every JavaScript interview in some form β from string validation to parsing. This guide builds regex knowledge from the ground up with practical examples.
Creating Regular Expressions
javascript-- Regex literal (preferred) const pattern = /hello/; -- RegExp constructor (use when pattern is dynamic) const word = "hello"; const dynamic = new RegExp(word, "i"); -- case-insensitive const dynamic2 = new RegExp(`\\b${word}\\b`, "gi");
Testing and Matching
javascriptconst pattern = /cat/; -- test() -- returns true/false pattern.test("I have a cat"); -- true pattern.test("I have a dog"); -- false -- match() -- returns array of matches or null "I have a cat and a catfish".match(/cat/g); -- ["cat", "cat"] "hello".match(/xyz/); -- null -- exec() -- returns match info, advances lastIndex (with /g flag) const re = /\d+/g; const str = "abc 123 def 456"; re.exec(str); -- ["123", index: 4, ...] re.exec(str); -- ["456", index: 12, ...] re.exec(str); -- null (no more matches) -- matchAll() -- iterator of all matches (with /g flag) for (const match of "test1 test2".matchAll(/test(\d)/g)) { console.log(match[0], match[1]); -- "test1" "1", then "test2" "2" } -- search() -- returns index of first match or -1 "hello world".search(/world/); -- 6 -- replace() / replaceAll() "hello world".replace(/world/, "JavaScript"); -- "hello JavaScript" "aabbcc".replace(/b/g, "X"); -- "aaXXcc" "aabbcc".replaceAll("b", "X"); -- "aaXXcc" -- split() "one,two;three".split(/[,;]/); -- ["one", "two", "three"]
Character Classes
javascript/[aeiou]/ -- any vowel /[^aeiou]/ -- any non-vowel (^ inside [] negates) /[a-z]/ -- any lowercase letter /[A-Z]/ -- any uppercase letter /[0-9]/ -- any digit /[a-zA-Z0-9]/ -- any alphanumeric -- Shorthand classes /\d/ -- digit [0-9] /\D/ -- non-digit [^0-9] /\w/ -- word char [a-zA-Z0-9_] /\W/ -- non-word /\s/ -- whitespace (space, tab, newline) /\S/ -- non-whitespace /./ -- any char except newline (with /s flag, includes newline) -- Examples /^\d{5}$/.test("12345"); -- true (5-digit zip code) /^\d{5}$/.test("1234"); -- false /\w+@\w+\.\w+/.test("a@b.c"); -- true (simple email check)
Quantifiers
javascript/a?/ -- 0 or 1 "a" /a*/ -- 0 or more "a" /a+/ -- 1 or more "a" /a{3}/ -- exactly 3 "a" /a{2,4}/ -- 2 to 4 "a" /a{2,}/ -- 2 or more "a" -- Greedy vs lazy "<b>bold</b>".match(/<.+>/)[0]; -- "<b>bold</b>" (greedy -- matches as much as possible) "<b>bold</b>".match(/<.+?>/)[0]; -- "<b>" (lazy -- matches as little as possible)
Anchors and Boundaries
javascript/^hello/ -- "hello" at start of string /world$/ -- "world" at end of string /^hello$/ -- exactly "hello" (nothing else) /\bcat\b/ -- whole word "cat" (not "catfish" or "scat") /\Bcat\B/ -- "cat" NOT at word boundary (inside a word) "cat catches cats".match(/\bcat\b/g); -- ["cat"] (only the standalone word) "cat catches cats".match(/\bcat/g); -- ["cat", "cat"] (words starting with cat)
Groups and Capturing
javascript-- Capturing group: () "2025-03-11".match(/(\d{4})-(\d{2})-(\d{2})/); -- ["2025-03-11", "2025", "03", "11"] -- match[1] = "2025", match[2] = "03", match[3] = "11" -- Named capturing groups: (?<name>) const { groups } = "2025-03-11".match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/); groups.year; -- "2025" groups.month; -- "03" groups.day; -- "11" -- Non-capturing group: (?:) "colour color".match(/colo(?:u)?r/g); -- ["colour", "color"] -- Backreference: \1 refers to what group 1 matched /<(\w+)>.*<\/\1>/.test("<div>hello</div>"); -- true /<(\w+)>.*<\/\1>/.test("<div>hello</span>"); -- false (tags don't match)
Lookahead and Lookbehind
javascript-- Positive lookahead (?=...): match if followed by /\d+(?= dollars)/.exec("100 dollars 50 euros"); -- ["100"] -- Negative lookahead (?!...): match if NOT followed by /\d+(?! dollars)/.exec("100 dollars 50 euros"); -- ["50"] -- Positive lookbehind (?<=...): match if preceded by /(?<=\$)\d+/.exec("$100 and β¬50"); -- ["100"] -- Negative lookbehind (?<!...): match if NOT preceded by /(?<!\$)\d+/.exec("$100 and 50"); -- ["50"] -- Password validation using lookaheads function isStrongPassword(password) { return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%]).{8,}$/.test(password); } -- ^ -- start -- (?=.*[a-z]) -- must contain lowercase -- (?=.*[A-Z]) -- must contain uppercase -- (?=.*\d) -- must contain digit -- (?=.*[!@#$%]) -- must contain special char -- .{8,} -- at least 8 characters -- $ -- end
Flags
javascript/pattern/g -- global: find all matches (not just first) /pattern/i -- case-insensitive /pattern/m -- multiline: ^ and $ match start/end of each line /pattern/s -- dotAll: . matches newlines too /pattern/u -- unicode: proper Unicode support /pattern/gi -- combine flags -- Multiline example const text = "line1\nline2\nline3"; text.match(/^\w+/gm); -- ["line1", "line2", "line3"] (without /m: ["line1"])
Common Practical Patterns
javascript-- Email validation (simplified -- true email validation is complex) const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; -- URL const urlRegex = /^https?:\/\/[\w\-.]+(:\d+)?(\/[^\s]*)?$/; -- Phone number (flexible) const phoneRegex = /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/; -- Slug (URL-friendly string) const slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/; -- Hex color const hexColor = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/; -- Extract all URLs from text const urls = text.match(/https?:\/\/[^\s]+/g) || []; -- Convert camelCase to kebab-case "camelCaseString".replace(/([A-Z])/g, "-$1").toLowerCase(); -- "camel-case-string" -- Trim whitespace (alternative to .trim()) " hello ".replace(/^\s+|\s+$/g, ""); -- "hello" -- Remove HTML tags "<p>Hello <b>World</b></p>".replace(/<[^>]*>/g, ""); -- "Hello World" -- Extract numbers from string "abc123def456".match(/\d+/g); -- ["123", "456"]
Advanced: Replace with a Function
javascript-- Capitalize first letter of each word "hello world foo".replace(/\b\w/g, char => char.toUpperCase()); -- "Hello World Foo" -- Template variable substitution const template = "Hello, {name}! You have {count} messages."; const vars = { name: "Alice", count: 5 }; template.replace(/\{(\w+)\}/g, (match, key) => vars[key] ?? match); -- "Hello, Alice! You have 5 messages." -- Highlight search terms in HTML function highlight(text, term) { const regex = new RegExp(`(${term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})`, "gi"); return text.replace(regex, "<mark>$1</mark>"); } highlight("I love JavaScript", "java"); -- "I love <mark>Java</mark>Script"
Common Interview Questions
Q: What is the difference between greedy and lazy quantifiers?
Greedy quantifiers (*, +, {n,}) match as much as possible while still allowing the overall pattern to match. Lazy quantifiers (*?, +?, {n,}?) match as little as possible. Example: /<.+>/ on "<b>text</b>" matches the entire string (greedy). /<.+?>/ matches only "<b>" (lazy).
Q: What does the g flag do and why does it affect exec()?
The g flag finds all matches instead of just the first. It also makes the regex stateful β it tracks lastIndex, the position to start the next search. Each exec() call advances lastIndex and returns the next match. This is why you must be careful using a regex with /g flag in a loop β the lastIndex persists between calls.
Q: How do you escape special characters in a dynamic regex pattern?
Special characters like ., *, +, ?, (, ), [, ], {, }, \, ^, $, | have meaning in regex. To match them literally when building patterns from user input, escape them:
userInput.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")Practice JavaScript on Froquiz
Regular expressions and string manipulation appear in JavaScript interviews at all levels. Test your JavaScript knowledge on Froquiz β from fundamentals to advanced patterns.
Summary
- Use
/pattern/flagsliterals ornew RegExp(pattern, flags)for dynamic patterns test()returns boolean;match()returns matches;replace()substitutes- Character classes
[abc], shorthand\d \w \s, anchors^ $, word boundary\b - Quantifiers:
?(0-1),*(0+),+(1+),{n,m}(range) β append?for lazy - Capturing groups
()extract parts; named groups(?<name>)for readable extraction - Lookaheads
(?=...)and lookbehinds(?<=...)match based on context without capturing - Flags:
g(all matches),i(case-insensitive),m(multiline),s(dotAll) - Always escape user input before using it in a dynamic
RegExp