Regular Expressions (Regex) in JavaScript

Search, validate and replace text with regular expressions: patterns, character classes, quantifiers, groups, flags, test, match and replace.

Lesson 32 of 56Intermediate15 min read

Some text problems are awkward with ordinary string methods. Check that a postcode has the right shape. Find every hashtag in a post. Replace all runs of spaces with a single space. Pull the numbers out of "Order 42: 3 items, £18.50". You could write loops for each, but regular expressions, usually shortened to regex, solve them in one line.

A regular expression is a small pattern language for describing text. /\d+/ means "one or more digits". /^[A-Z]/ means "starts with a capital letter". Patterns like these work in JavaScript, Python, Java, databases, code editors and the command line, so learning them pays off far beyond this course.

Regex has a reputation for looking like line noise, but you only need a core set of symbols for most everyday tasks. In this lesson you'll learn that core: character classes, quantifiers, anchors, groups and flags, and the methods test, match, matchAll, replace and split. You already know the plain string methods; regex makes them far more powerful.

Creating a regex and testing it

JavaScript
const pattern = /cat/i;          // literal: between slashes, flags after
const dynamic = new RegExp("cat", "i"); // from a string, e.g. user input

pattern.test("Concatenate");     // true
  • A regex literal is written between slashes: /pattern/flags.
  • test(text) returns true or false. It's the method to use for validation.
  • Most characters match themselves. Special characters such as . * + ? ( ) [ ] { } ^ $ | \ / need a backslash to match literally: /\./ matches a real full stop.

Character classes and quantifiers

PatternMatches
\dAny digit, 0 to 9
\wA letter, digit or underscore
\sWhitespace: space, tab, new line
.Any character except a new line
[aeiou]Any one of these characters
[A-Z] [0-9a-f]A range of characters
[^0-9]Anything except these
\D \W \SThe opposite of \d, \w, \s
QuantifierMeans
+One or more
*Zero or more
?Zero or one (optional)
{3}Exactly 3
{2,5}Between 2 and 5

Anchors, groups and flags

SymbolMeaningExample
^Start of the text/^Hi/ matches "Hi there"
$End of the text/\.pdf$/ matches "cv.pdf"
\bWord boundary/\bcat\b/ skips "concatenate"
( )A group you can capture/(\d+)-(\d+)/
(?<name> )A named group/(?<year>\d{4})/
a|bEither a or b/jpg|png/
FlagEffect
gGlobal: find all matches, not just the first
iIgnore case
m^ and $ match at each line
uFull Unicode support

For validation, anchor the pattern at both ends with ^...$, otherwise it passes when the pattern appears anywhere inside the text.

Methods that use regex

MethodReturnsExample
regex.test(str)true or false/^\d{4}$/.test("2026")
str.match(regex)First match with groups, or all matches with g"a1b22".match(/\d+/g) gives ["1", "22"]
str.matchAll(regex)An iterator of every match with groups (needs g)Loop with for...of
str.replace(regex, x)A new string"a b".replace(/\s+/g, " ")
str.split(regex)An array"a, b;c".split(/[,;]\s*/)

In replace, $1 and $<name> insert captured groups, and you can pass a function to build each replacement.

JavaScript Regex Syntax

Regex quick reference

/^\d{5}$/.test("12345");                 // exactly five digits
"Tel: 07700 900123".match(/\d+/g);       // ["07700", "900123"]
"2026-03-14".replace(/(\d+)-(\d+)-(\d+)/, "$3/$2/$1"); // "14/03/2026"
"Hello   world".replace(/\s+/g, " ");    // "Hello world"
const { year } = "2026-03".match(/(?<year>\d{4})/).groups;

JavaScript Regex Summary

  • A regex describes a text pattern: /pattern/flags.
  • \d, \w, \s and [...] match kinds of characters; +, *, ? and {n} repeat them.
  • ^ and $ anchor a pattern to the start and end, which is essential for validation.
  • Parentheses capture groups; the g flag finds every match and i ignores case.
  • Use test to validate, match and matchAll to extract, and replace to transform.

JavaScript Regex Examples

Each example runs in the page. Edit the code and press Run to see what changes.

Example 1

Validating input

const checks = {
  postcode: /^[A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}$/i,
  pin: /^\d{4}$/,
  username: /^[a-z][a-z0-9_]{2,14}$/,
  hex: /^#([0-9a-f]{3}|[0-9a-f]{6})$/i,
};

const samples = { postcode: "SW1A 1AA", pin: "12a4", username: "sam_99", hex: "#1E90FF" };

for (const [field, pattern] of Object.entries(checks)) {
  console.log(field, samples[field], pattern.test(samples[field]) ? "valid" : "invalid");
}
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 2A UK postcode shape; i allows lower case and ? makes the space optional.
  2. Line 3Exactly four digits, anchored at both ends, so "12a4" fails.
  3. Line 4Starts with a letter, then 2 to 14 more letters, digits or underscores.
  4. Line 5A hex colour with either 3 or 6 hex digits.
  5. Lines 10 to 11Loop over every check and test its sample.
Example 2

Extracting data

const post = "Loving the #sunset at #Brighton today! Tickets £12.50, doors 19:30";

const tags = post.match(/#\w+/g);
console.log("Tags:", tags);

const price = post.match(/£(\d+\.\d{2})/);
console.log("Price:", Number(price[1]));

const time = post.match(/(?<h>\d{2}):(?<m>\d{2})/);
console.log("Hour:", time.groups.h, "Minute:", time.groups.m);

for (const m of "a1 b22 c333".matchAll(/([a-z])(\d+)/g)) {
  console.log(`letter ${m[1]} has ${m[2].length} digits`);
}
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 3With g, match returns every hashtag.
  2. Line 6Without g, the result includes groups; price[1] is the first captured group.
  3. Line 9Named groups are easier to read than numbers.
  4. Line 12matchAll gives every match with its groups.
Example 3

Cleaning and transforming text

const messy = "  Hello    there,   how are   you?  ";
console.log(`"${messy.trim().replace(/\s+/g, " ")}"`);

const date = "2026-03-14";
console.log(date.replace(/(\d{4})-(\d{2})-(\d{2})/, "$3/$2/$1"));

const title = "the quick brown fox";
console.log(title.replace(/\b\w/g, (letter) => letter.toUpperCase()));

const card = "4111 1111 1111 1234";
console.log(card.replace(/\d(?=(?:\s?\d){4})/g, "•"));

console.log("red, green;blue ,  yellow".split(/\s*[,;]\s*/));
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 2Trim the ends, then turn every run of whitespace into one space.
  2. Line 5Groups are reused in the replacement in a new order.
  3. Line 8A function replaces the first letter of every word with a capital.
  4. Line 11A lookahead hides every digit except the last four.
  5. Line 13Split on commas or semicolons with any spaces around them.

Common JavaScript Regex Mistakes

Forgetting anchors in validation

Don't
/\d{4}/.test("my PIN is 123456"); // true: four digits appear somewhere
Do
/^\d{4}$/.test("123456"); // false

Expecting replace to change every match without g

Don't
"a-b-c".replace(/-/, " "); // "a b-c"
Do
"a-b-c".replace(/-/g, " "); // "a b c"
"a-b-c".replaceAll("-", " "); // also fine for plain text

Not escaping special characters

Don't
/1.50/.test("1250"); // true: . means any character
Do
/1\.50/.test("1250"); // false

JavaScript Regex in Real Projects

Regex in practice

Form libraries use regex for phone numbers, postcodes and passwords. Code editors such as VS Code support regex search and replace across whole projects. Analytics tools filter URLs with patterns, log tools search errors, and routing libraries match paths like /users/:id with regular expressions behind the scenes. HTML's pattern attribute on inputs accepts the same syntax.

JavaScript Regex Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Make the pattern match one or more digits.

const hasNumber = /\d/;
console.log(hasNumber.test("Room 101"));
Predict the outputmedium

What is logged?

console.log("cat Cat CAT".match(/cat/gi).length, /^cat$/.test("cats"));
Multiple choiceeasy

Which method returns true or false?

Multiple choicemedium

What does [^0-9] match?

Fix the bugmedium

isValidCode should accept exactly two capital letters followed by exactly three digits, like "AB123". tidy should replace every run of spaces with a single space. Fix both patterns.

function isValidCode(code) {
  return /[A-Z]{2}\d{3}/.test(code);
}
function tidy(text) {
  return text.replace(/ +/, " ");
}
console.log(isValidCode("AB123"), isValidCode("xAB1234"), tidy("a   b   c"));
ConsoleEdit the code, then press Run or Ctrl+Enter
Checks
  • Accepts a valid code
  • Rejects extra characters
  • Tidies every gap

JavaScript Regex Quiz

5 questions to check what you learned.

  1. What does \d match?

    • A letter
    • A digit
    • A space
    • A dollar sign
  2. What does the g flag do?

    • Makes the match greedy
    • Groups the pattern
    • Ignores case
    • Finds all matches instead of only the first
  3. In "2026-03".replace(/(\d+)-(\d+)/, "$2/$1"), what is the result?

    • "03/2026"
    • "2026/03"
    • "$2/$1"
    • "03-2026"
  4. Which quantifier makes something optional?

    • +
    • ?
    • *
    • {2}
  5. Why does /\bcat\b/ not match "concatenate"?

    • It's case-sensitive
    • concatenate is too long
    • \b requires a word boundary on each side, so cat must be a whole word
    • \b means "begins with b"

JavaScript Regex Challenge

Extract and format phone numbers

Write findPhones(text):

  1. Find every UK mobile number in the text. They start with 07 and have 9 more digits, possibly with one space after the first five digits (for example 07700 900123 or 07700900123)
  2. Remove any spaces from each number
  3. Return an array of the cleaned numbers (an empty array if none are found)
function findPhones(text) {

}

console.log(findPhones("Call 07700 900123 or 07911123456. Office: 0207 946 0000"));
ConsoleEdit the code, then press Run or Ctrl+Enter
Checks
  • Finds both mobiles
  • Ignores landlines
  • Empty array when none