CodingNic

Strings and Regular Expressions

Regular Expressions

Strings and Regular Expressions 40 min read

Regular Expressions

Objectives

By the end of this chapter, you should be able to:

  • Explain what a regular expression is and when it beats .includes()
  • Write simple patterns using literal characters, character classes, quantifiers, and anchors
  • Group part of a pattern with ()
  • Test whether a string matches a pattern with .test()
  • Extract matches from a string with .match()
  • Search and replace using a pattern with .replace()

💡 Why this matters: .includes() can only check for exact text. A regular expression can describe a shape of text, like “a four-digit number” or “starts with a capital letter”, which is what real validation and searching usually need.

What Is a Regular Expression?

.includes() can only look for exact text you already know:

javascript
const text = "Order #4471 shipped";
console.log(text.includes("#4471"));
// true

That works only because you already knew the order number was 4471. If you wanted to check “does this text contain an order number after #?” without knowing the number in advance, .includes() can’t do it.

A regular expression (regex, for short) describes a pattern of text instead of one exact piece of text. In JavaScript, you write one between two forward slashes:

javascript
/pattern/

This lesson covers just enough regex to read and write simple, useful patterns: literal characters, character classes, quantifiers, anchors, and basic groups.

Literal Characters

The simplest pattern is just the characters you’re looking for, written plainly. /cat/ matches any string that contains c followed by a followed by t, anywhere inside it.

javascript
const catPattern = /cat/;
console.log(catPattern.test("concatenate"));
// true
console.log(catPattern.test("dog"));
// false

"concatenate" contains cat in the middle (con-cat-enate), so it matches, even though the word isn’t about cats at all. Regex patterns match anywhere in the string unless you tell them not to, which is where anchors come in later.

Character Classes

A character class, written in square brackets, matches any one character from a set. [aeiou] matches a single character that is a, e, i, o, or u.

javascript
const vowelPattern = /[aeiou]/;
console.log(vowelPattern.test("sky"));
// false
console.log(vowelPattern.test("cat"));
// true

"sky" has no vowel in that class (y doesn’t count), so it fails. "cat" contains a, so it matches.

JavaScript also has shorthand classes for common cases:

  • \d matches any digit (0 to 9)
  • \w matches any “word” character (letters, digits, and underscore)
  • \s matches any whitespace (space, tab, newline)
javascript
const digitPattern = /\d/;
console.log(digitPattern.test("Order 42"));
// true
console.log(digitPattern.test("Order"));
// false
javascript
const wordCharPattern = /\w/;
console.log(wordCharPattern.test("!"));
// false
console.log(wordCharPattern.test("a"));
// true
javascript
const spacePattern = /\s/;
console.log(spacePattern.test("hello world"));
// true
console.log(spacePattern.test("helloworld"));
// false

Quantifiers

A quantifier says how many times the thing right before it can repeat.

  • * means “zero or more”
  • + means “one or more”
  • ? means “zero or one” (optional)
  • {n} means “exactly n”

\d+ means “one or more digits in a row”:

javascript
const digitsPattern = /\d+/;
console.log(digitsPattern.test("Order 4471"));
// true
console.log("Order 4471".match(digitsPattern));
// [ '4471', index: 6, input: 'Order 4471', groups: undefined ]

colou?r means “colo, then an optional u, then r”, which matches both American and British spelling:

javascript
const colorPattern = /colou?r/;
console.log(colorPattern.test("color"));
// true
console.log(colorPattern.test("colour"));
// true

\d{4} means “exactly four digits in a row”:

javascript
const codePattern = /^\d{4}$/;
console.log(codePattern.test("4471"));
// true
console.log(codePattern.test("447"));
// false
console.log(codePattern.test("44715"));
// false

That example also uses ^ and $, covered next. Without them, \d{4} would still match the first four digits inside a longer number like "44715".

Anchors

^ and $ don’t match a character. They match a position: the very start or the very end of the string.

^ anchors the pattern to the start:

javascript
const startsWithHi = /^Hi/;
console.log(startsWithHi.test("Hi there"));
// true
console.log(startsWithHi.test("Say Hi"));
// false

$ anchors the pattern to the end:

javascript
const endsWithBang = /!$/;
console.log(endsWithBang.test("Watch out!"));
// true
console.log(endsWithBang.test("Watch out! Really"));
// false

Used together, as in /^\d{4}$/ above, they mean “the entire string, start to finish, must be exactly four digits.” That’s different from /\d{4}/ alone, which is happy to find four digits anywhere inside a longer string.

Grouping with ()

Parentheses group part of a pattern together. One common use is pulling specific pieces out of a match. Each group becomes an item you can read back from the match result.

javascript
const datePattern = /(\d{4})-(\d{2})-(\d{2})/;
const result = "2026-07-25".match(datePattern);
console.log(result[0]);
// 2026-07-25
console.log(result[1]);
// 2026
console.log(result[2]);
// 07
console.log(result[3]);
// 25

result[0] is always the whole match. result[1], result[2], and result[3] are the year, month, and day, each captured by its own set of parentheses.

Testing a Match with .test()

.test() is the method you’ve been using throughout this lesson. It runs a pattern against a string and returns true or false, nothing more. Reach for it whenever you just need a yes-or-no answer, like validating input.

Extracting Matches with .match()

.match() runs a pattern against a string and gives you back the actual text that matched, instead of just true or false.

Without a g (global) flag, .match() stops at the first match:

javascript
console.log("Order 4471".match(/\d+/));
// [ '4471', index: 6, input: 'Order 4471', groups: undefined ]

With the g flag, .match() finds every match in the string and returns them as a plain array:

javascript
const orders = "Order 4471, Order 5522";
console.log(orders.match(/\d+/g));
// [ '4471', '5522' ]

Search and Replace with .replace()

You already used .replace() with a plain string in the last lesson, which only replaces the first match. Pass it a regex with the g flag instead, and it replaces every match.

javascript
const messy = "Erin   Jordan     Maya";
console.log(messy.replace(/\s+/g, " "));
// Erin Jordan Maya

\s+ matches one or more whitespace characters, so every run of extra spaces, no matter how long, collapses down to a single space.

Putting It Together: A Simple Email Check

Here’s a basic pattern that checks whether a string has the rough shape of an email address: some word characters, an @, more word characters, a literal dot, and more word characters, with nothing extra before or after.

javascript
const emailPattern = /^\w+@\w+\.\w+$/;
console.log(emailPattern.test("priya@example.com"));
// true
console.log(emailPattern.test("not-an-email"));
// false
console.log(emailPattern.test("priya@example"));
// false

Be honest about the limits here: this is a beginner-level shape check, not a real email validator. \w doesn’t include dots, so it rejects perfectly valid addresses with a dot in the local part or more than one dot in the domain:

javascript
const emailPattern = /^\w+@\w+\.\w+$/;
console.log(emailPattern.test("priya.j@example.co.uk"));
// false

Real email validation is a much deeper rabbit hole than it looks (the official spec allows some very strange addresses). For a fundamentals course, the lesson here is the pattern-building skill, not a production-ready validator.

Try It

  1. Write a pattern that matches a string containing at least one digit. Test it against "room42" and "room".
  2. Write a pattern, using an anchor, that checks whether a string starts with "Error". Test it against "Error: disk full" and "Fatal Error".
  3. Use .replace() with a regex to collapse "Sam just arrived" down to single spaces between words.
  4. Write a pattern with a group that pulls the number out of "id:482", and log just the captured number.
  5. Write a pattern that matches a string of exactly three digits, and confirm it rejects both "48" and "4820".

Recap

  • A regular expression describes a pattern of text, not one exact piece of text.
  • Character classes like [abc], \d, \w, and \s match one character from a set.
  • Quantifiers (*, +, ?, {n}) say how many times the previous piece can repeat.
  • Anchors (^, $) match the start and end of a string, not a character.
  • Parentheses () group part of a pattern and let you pull specific pieces out of a match.
  • .test() gives a yes-or-no answer. .match() gives you the matched text. .replace() with a g flag replaces every match.
  • Even a working regex can have real limits, like the email example here. Know what your pattern does and doesn’t cover.

Next lesson: exercises to practice string methods, template literals, and regular expressions together.