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
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)returnstrueorfalse. 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
| Pattern | Matches |
|---|---|
\d | Any digit, 0 to 9 |
\w | A letter, digit or underscore |
\s | Whitespace: 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 \S | The opposite of \d, \w, \s |
| Quantifier | Means |
|---|---|
+ | One or more |
* | Zero or more |
? | Zero or one (optional) |
{3} | Exactly 3 |
{2,5} | Between 2 and 5 |
Anchors, groups and flags
| Symbol | Meaning | Example |
|---|---|---|
^ | Start of the text | /^Hi/ matches "Hi there" |
$ | End of the text | /\.pdf$/ matches "cv.pdf" |
\b | Word boundary | /\bcat\b/ skips "concatenate" |
( ) | A group you can capture | /(\d+)-(\d+)/ |
(?<name> ) | A named group | /(?<year>\d{4})/ |
a|b | Either a or b | /jpg|png/ |
| Flag | Effect |
|---|---|
g | Global: find all matches, not just the first |
i | Ignore case |
m | ^ and $ match at each line |
u | Full 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
| Method | Returns | Example |
|---|---|---|
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,\sand[...]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
gflag finds every match andiignores case. - Use
testto validate,matchandmatchAllto extract, andreplaceto transform.
JavaScript Regex Examples
Each example runs in the page. Edit the code and press Run to see what changes.
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");
}Line-by-line explanation
- Line 2A UK postcode shape;
iallows lower case and?makes the space optional. - Line 3Exactly four digits, anchored at both ends, so "12a4" fails.
- Line 4Starts with a letter, then 2 to 14 more letters, digits or underscores.
- Line 5A hex colour with either 3 or 6 hex digits.
- Lines 10 to 11Loop over every check and test its sample.
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`);
}Line-by-line explanation
- Line 3With
g,matchreturns every hashtag. - Line 6Without
g, the result includes groups;price[1]is the first captured group. - Line 9Named groups are easier to read than numbers.
- Line 12
matchAllgives every match with its groups.
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*/));Line-by-line explanation
- Line 2Trim the ends, then turn every run of whitespace into one space.
- Line 5Groups are reused in the replacement in a new order.
- Line 8A function replaces the first letter of every word with a capital.
- Line 11A lookahead hides every digit except the last four.
- Line 13Split on commas or semicolons with any spaces around them.
Common JavaScript Regex Mistakes
Forgetting anchors in validation
/\d{4}/.test("my PIN is 123456"); // true: four digits appear somewhere/^\d{4}$/.test("123456"); // falseExpecting replace to change every match without g
"a-b-c".replace(/-/, " "); // "a b-c""a-b-c".replace(/-/g, " "); // "a b c"
"a-b-c".replaceAll("-", " "); // also fine for plain textNot escaping special characters
/1.50/.test("1250"); // true: . means any character/1\.50/.test("1250"); // falseJavaScript 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.
Make the pattern match one or more digits.
const hasNumber = /\d/;
console.log(hasNumber.test("Room 101"));
+ means one or more.What is logged?
console.log("cat Cat CAT".match(/cat/gi).length, /^cat$/.test("cats"));Which method returns true or false?
What does [^0-9] match?
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"));- Accepts a valid code
- Rejects extra characters
- Tidies every gap
JavaScript Regex Quiz
5 questions to check what you learned.
What does \d match?
- A letter
- A digit
- A space
- A dollar sign
What does the g flag do?
- Makes the match greedy
- Groups the pattern
- Ignores case
- Finds all matches instead of only the first
In "2026-03".replace(/(\d+)-(\d+)/, "$2/$1"), what is the result?
- "03/2026"
- "2026/03"
- "$2/$1"
- "03-2026"
Which quantifier makes something optional?
- +
- ?
- *
- {2}
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):
- Find every UK mobile number in the text. They start with
07and have 9 more digits, possibly with one space after the first five digits (for example07700 900123or07700900123) - Remove any spaces from each number
- 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"));- Finds both mobiles
- Ignores landlines
- Empty array when none