Regular expressions
Why it matters
String methods (includes, indexOf, split) search for specific text. But you often need to find text of
a certain kind: "six digits in a row", "a word after #", "something that looks like an email". That's what
regular expressions (regex for short) are for — a small language of patterns.
They are everywhere: checking form fields (email, phone, password), search and replace in a code editor, parsing logs, processing data from websites. You don't have to memorize regex, but every programmer should be able to read and write simple patterns.
How to write a pattern
A regular expression is written between two slashes. The test method tells you whether the string has a match:
const pattern = /cat/;
console.log(pattern.test("My cat is sleeping"));
console.log(pattern.test("My dog is sleeping"));
Output:
true
false
After the second slash you write flags: /cat/i — ignore case, /cat/g — find all matches, not just the first.
Character classes
Instead of a specific letter you can specify a kind of character:
| Pattern | What matches |
|---|---|
\d |
a digit 0–9 |
\w |
a Latin letter, digit or _ |
\s |
a whitespace character: space, tab, line break |
\D, \W, \S |
the opposite: not a digit, not a letter, not a space |
. |
any character except a line break |
[abc] |
one of the characters a, b, c |
[a-z], [0-9] |
a range |
[^0-9] |
anything except the listed ones |
console.log(/\d\d:\d\d/.test("Meeting at 14:30"));
console.log(/[aeiou]/i.test("HELLO"));
Output:
true
true
A dot, brackets, +, ? and other characters have a special meaning. To find them literally, put a backslash
before them: \. — exactly a dot, \( — exactly a bracket.
Quantifiers: how many times
| Pattern | How many |
|---|---|
a+ |
one or more |
a* |
zero or more |
a? |
zero or one (optional) |
a{3} |
exactly 3 |
a{2,4} |
from 2 to 4 |
a{2,} |
2 or more |
console.log("Prices: 5, 120 and 3500 somoni".match(/\d+/g));
console.log(/^colou?r$/.test("color"), /^colou?r$/.test("colour"));
Output:
["5","120","3500"]
true true
Start and end of the string
^ means the start of the string, $ — the end. Without them a pattern looks for a match anywhere inside the
string — a common cause of bugs when checking forms:
console.log(/\d{4}/.test("year 2026!")); // four digits somewhere inside
console.log(/^\d{4}$/.test("year 2026!")); // the whole string is four digits
console.log(/^\d{4}$/.test("2026"));
Output:
true
false
true
Groups and "or"
Parentheses join part of a pattern into a group: you can apply a quantifier to it, and you can get its content
separately. The vertical bar | means "or":
console.log(/^(ha)+$/.test("hahaha"));
console.log(/^(cat|dog)s?$/.test("dogs"));
const m = "Date: 2026-11-02".match(/(\d{4})-(\d{2})-(\d{2})/);
console.log(m[0]); // the whole match
console.log(m[1], m[2], m[3]); // the groups in order
Output:
true
true
2026-11-02
2026 11 02
Groups can have names — then the code reads better:
const { groups } = "2026-11-02".match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/);
console.log(groups.day + "." + groups.month + "." + groups.year);
Output:
02.11.2026
Methods: find all matches
| Method | What it does |
|---|---|
regex.test(str) |
is there a match → true / false |
str.match(regex) |
without g: the first match with groups (or null); with g: an array of all matches |
str.matchAll(regex) |
all matches with groups (needs the g flag) |
str.replace(regex, replacement) |
replace (all of them with the g flag) |
str.split(regex) |
split by a pattern |
matchAll goes through all matches, and each has groups:
const text = "Ann: 5, Timur: 4, Lola: 5";
for (const m of text.matchAll(/([A-Za-z]+): (\d)/g)) {
console.log(m[1] + " got " + m[2]);
}
Output:
Ann got 5
Timur got 4
Lola got 5
To get an array, spread the matches: [...text.matchAll(/…/g)].
Greediness
The quantifiers + and * are greedy: they take as many characters as possible. Sometimes that's not what
you want:
const html = "<b>one</b> and <b>two</b>";
console.log(html.match(/<b>.+<\/b>/)[0]); // greedy: from the first <b> to the last </b>
console.log(html.match(/<b>.+?<\/b>/)[0]); // ? after + — as few as possible
Output:
<b>one</b> and <b>two</b>
<b>one</b>
This is the main lesson of regex: a pattern does exactly what is written. Describe the allowed characters as precisely as you can and test the pattern on several examples.
Replacing
In replace you can insert groups: $1, $2… — or pass a function that returns the replacement:
console.log("2026-11-02".replace(/(\d{4})-(\d{2})-(\d{2})/, "$3.$2.$1"));
console.log(" lots of spaces ".trim().replace(/\s+/g, " "));
console.log("price 100 and 250".replace(/\d+/g, (n) => n * 2));
Output:
02.11.2026
lots of spaces
price 200 and 500
And splitting by a pattern — for example, by commas with any spaces around them:
console.log("apples ,pears, plums".split(/\s*,\s*/));
Output:
["apples","pears","plums"]
How it works inside
The regex engine walks along the string from left to right and at each position tries to "fit" the pattern.
Quantifiers are greedy by default: .+ first takes everything up to the end of the string and then gives
characters back until the rest of the pattern matches. If you need to take as few as possible, put ? after
the quantifier: .+?.
A regular expression with the g flag remembers where it stopped (the lastIndex property). That's why the
same /…/g object can give different answers on repeated test calls. You don't need the g flag for test checks.
Common mistakes
- No
^and$in a check./\d{6}/lets"abc1234567xyz"through: there are six digits in it. - An unescaped dot.
/a.b/also matches"a-b". A literal dot is\.. - A forgotten
gflag.replacewithoutgreplaces only the first match, andmatchAllwithoutgthrows an error. \wand non-Latin letters.\wis only Latin letters, digits and_. For Cyrillic letters write[А-Яа-яЁё].- A pattern that's too complex. If a regex doesn't fit in your head, split the task into steps: first clean the string, then check it.
Cheat sheet
| What | How |
|---|---|
| Is there a match | /pattern/.test(str) |
| All matches | str.match(/pattern/g) |
| With groups | [...str.matchAll(/(..)/g)] |
| Replace all | str.replace(/pattern/g, "new") |
| Digit, letter, space | \d, \w, \s |
| Not a digit | \D |
| How many times | +, *, ?, {n}, {n,m} |
| The whole string | ^…$ |
| Group, "or" | (…), `a |
| Ignore case | flag i |