JSON in JavaScript
A regular expression (regex) is a pattern that describes a set of strings. You use it to search for text, check if a value matches a certain format, or replace parts of a string.
Think of it like a search filter. Instead of searching for one exact word, you describe a shape of text — "a string that starts with a digit, followed by three letters, ending in @". Regex lets you express that shape in a compact notation.
You create a regex in JavaScript in two ways:
// 1. Regex literal — the most common way
const pattern = /hello/;
// 2. RegExp constructor — useful when the pattern is dynamic
const word = "hello";
const pattern2 = new RegExp(word);
// Test a string against the pattern
console.log(pattern.test("say hello there")); // true
console.log(pattern.test("goodbye")); // false
Regex is not just a JavaScript thing — it exists in almost every programming language. Once you understand it here, the core ideas carry over everywhere.
A regex literal is written between two forward slashes: /pattern/. After the closing slash you can add flags like g, i, or m to change how the match works.
// Pattern: match the word "cat" (case-sensitive)
const pattern = /cat/;
console.log(pattern.test("The cat sat")); // true
console.log(pattern.test("The Cat sat")); // false — uppercase C
// With the i flag: case-insensitive
const patternI = /cat/i;
console.log(patternI.test("The Cat sat")); // true
Special characters in regex have reserved meanings. If you want to match a literal ., *, +, ?, (, ), [, {, \, ^, $, or |, you must escape them with a backslash:
// . without escape matches ANY character
/c.t/.test("c@t"); // true — . matches @
// \. matches a literal dot
/c\.t/.test("c.t"); // true
/c\.t/.test("c@t"); // false
Character classes let you match one character from a set. You define a class with square brackets [...].
- [abc] — matches a, b, or c
- [^abc] — matches any character that is not a, b, or c
- [a-z] — any lowercase letter
- [A-Z] — any uppercase letter
- [0-9] — any digit
- [a-zA-Z0-9] — any letter or digit
There are also built-in shorthand classes:
- \d — any digit (same as [0-9])
- \D — any non-digit
- \w — any word character: letters, digits, underscore (same as [a-zA-Z0-9_])
- \W — any non-word character
- \s — any whitespace (space, tab, newline)
- \S — any non-whitespace
- . — any character except newline
console.log(/\d/.test("abc3")); // true — contains a digit
console.log(/\d/.test("abcdef")); // false — no digits
console.log(/\w/.test("hello_1")); // true
console.log(/\s/.test("hi there")); // true — has a space
console.log(/[aeiou]/.test("sky")); // false — no vowels
Quantifiers control how many times a character or group must appear to count as a match.
- * — 0 or more times
- + — 1 or more times
- ? — 0 or 1 time (makes it optional)
- {n} — exactly n times
- {n,} — at least n times
- {n,m} — between n and m times
// + means one or more digits
console.log(/\d+/.test("abc123")); // true
console.log(/\d+/.test("abcdef")); // false
// {3} means exactly 3 digits
console.log(/\d{3}/.test("12")); // false
console.log(/\d{3}/.test("123")); // true
console.log(/\d{3}/.test("1234")); // true — "123" matches inside it
// ? makes the 's' optional
console.log(/colou?r/.test("color")); // true
console.log(/colou?r/.test("colour")); // true
By default, quantifiers are greedy — they match as much as possible. Add ? after a quantifier to make it lazy (match as little as possible):
const str = "bold and more";
// Greedy: matches as much as possible
const greedy = str.match(/.*<\/b>/);
console.log(greedy[0]); // bold and more (too much)
// Lazy: matches as little as possible
const lazy = str.match(/.*?<\/b>/);
console.log(lazy[0]); // bold (just the first)
Anchors do not match characters. They match a position in the string. This lets you say "this pattern must appear at the start" or "must appear at the end".
- ^ — matches the start of the string
- $ — matches the end of the string
- \b — matches a word boundary (between a word character and a non-word character)
- \B — matches a non-word boundary
// ^ anchors to the start
console.log(/^Hello/.test("Hello world")); // true
console.log(/^Hello/.test("Say Hello")); // false
// $ anchors to the end
console.log(/world$/.test("Hello world")); // true
console.log(/world$/.test("world peace")); // false
// ^ and $ together: exact full-string match
console.log(/^\d{5}$/.test("12345")); // true — exactly 5 digits
console.log(/^\d{5}$/.test("1234")); // false
console.log(/^\d{5}$/.test("123456")); // false
// \b word boundary
console.log(/\bcat\b/.test("the cat sat")); // true
console.log(/\bcat\b/.test("concatenate")); // false
Parentheses (...) create a capturing group. They let you apply a quantifier to a whole sub-pattern, and also capture the matched text so you can use it later.
// Group with quantifier: (ab)+ means "ab" repeated one or more times
console.log(/(ab)+/.test("ababab")); // true
console.log(/(ab)+/.test("aab")); // false
// Capture groups in match()
const date = "2026-04-06";
const match = date.match(/(\d{4})-(\d{2})-(\d{2})/);
console.log(match[0]); // "2026-04-06" — full match
console.log(match[1]); // "2026" — group 1
console.log(match[2]); // "04" — group 2
console.log(match[3]); // "06" — group 3
Use (?:...) for a non-capturing group when you need grouping for a quantifier but don't need to capture the value:
// (?:ab)+ groups but does not capture
const m = "ababab".match(/(?:ab)+/);
console.log(m[0]); // "ababab" — full match
console.log(m[1]); // undefined — no capture group
You can also use the | (pipe) character as an OR operator inside or outside a group:
// Match "cat" or "dog"
console.log(/cat|dog/.test("I have a dog")); // true
console.log(/cat|dog/.test("I have a fish")); // false
// Group the OR to apply a quantifier
console.log(/(cat|dog)s?/.test("cats")); // true
console.log(/(cat|dog)s?/.test("dogs")); // true
Flags go after the closing slash and change how matching works. You can combine multiple flags.
- i — case-insensitive matching
- g — global: find all matches, not just the first
- m — multiline: ^ and $ match start/end of each line, not the whole string
- s — dot-all: . matches newlines too
- u — Unicode mode
- d — return start/end indices for each match (ES2022)
// i flag — case-insensitive
console.log(/hello/i.test("HELLO WORLD")); // true
// g flag — find all matches
const str = "cat bat sat";
const all = str.match(/[a-z]at/g);
console.log(all); // ["cat", "bat", "sat"]
// Without g — only the first match
const first = str.match(/[a-z]at/);
console.log(first[0]); // "cat"
// m flag — multiline
const multi = "line1\nline2\nline3";
const lines = multi.match(/^\w+/gm);
console.log(lines); // ["line1", "line2", "line3"]
You can use regex with both RegExp methods and String methods.
RegExp methods:
- regex.test(str) — returns true or false
- regex.exec(str) — returns match array with index info, or null
const regex = /\d+/;
console.log(regex.test("abc 123")); // true
console.log(regex.test("no nums")); // false
const result = regex.exec("abc 123 def");
console.log(result[0]); // "123"
console.log(result.index); // 4 — position in string
String methods that accept regex:
- str.match(regex) — returns array of matches (or null)
- str.matchAll(regex) — returns iterator of all matches with details (requires g flag)
- str.search(regex) — returns index of first match, or -1
- str.replace(regex, replacement) — replaces match with a string or function
- str.replaceAll(regex, replacement) — replaces all matches (requires g flag)
- str.split(regex) — splits string at each match
const str = "Hello World 2026";
// match — returns array
console.log(str.match(/\d+/)); // ["2026", index: 12, ...]
console.log(str.match(/\d+/g)); // ["2026"]
// search — returns index
console.log(str.search(/World/)); // 6
console.log(str.search(/xyz/)); // -1
// replace — swap matched text
console.log(str.replace(/World/, "JavaScript")); // "Hello JavaScript 2026"
// replace with a function
const result = "cat and dog".replace(/cat|dog/g, match => match.toUpperCase());
console.log(result); // "CAT and DOG"
// split on whitespace
console.log("one two three".split(/\s+/)); // ["one", "two", "three"]
- A regular expression is a pattern that matches text. Create one with a literal /pattern/ or new RegExp("pattern").
- Character classes: [abc] matches one of those chars. Shorthands: \d (digit), \w (word char), \s (whitespace).
- Quantifiers: * (0+), + (1+), ? (0 or 1), {n,m} (range). Add ? after one to make it lazy.
- Anchors: ^ = start, $ = end. Together they force an exact full-string match. \b = word boundary.
- Groups: (abc) captures. (?:abc) groups without capturing. | = OR.
- Flags: i = case-insensitive, g = find all matches, m = multiline anchors.
- Key methods: regex.test() (boolean), str.match() (array), str.replace() (new string), str.split() (array).
- Quantifiers are greedy by default — they match as much as possible. Append ? to make them lazy.
- What is a regular expression and what is it used for?
- What is the difference between creating a regex with a literal vs new RegExp()?
- What does the g flag do in a regular expression?
- What is the difference between + and * quantifiers?
- What is the difference between ^ inside square brackets and ^ outside?
- What is a capturing group and how do you access captured text?
- What is the difference between a greedy and a lazy quantifier?
- How would you check if a string contains only digits?
- How would you replace all occurrences of a word in a string using regex?
- What does \b match in a regular expression?