IntermediateJavaScript · Lesson 2 of 10

Regular Expressions

Validate and extract text with patterns: test, match, matchAll, named groups, replace and split.

A regular expression describes a text pattern. Write it as a literal between slashes, /^0[67]\d{8}$/, followed by flags: g finds every match, i ignores case. The essentials are \d (digit), \w (letter, digit or _), \s (whitespace), . (any character), classes like [67], quantifiers + * ? {8}, and the anchors ^ and $ for the start and end. \b marks a word boundary.

regex.test(text) answers yes or no. text.match(regex) without g returns the first match and its capture groups; with g it returns every matched string. text.matchAll(regex) (needs g) gives full match objects for every match, and named groups (?<score>\d+) make the results readable through m.groups.

text.replace(regex, "$1 $2") rewrites matches using the groups, and passing a function lets you compute each replacement. text.split(/\s*,\s*/) splits on a pattern. Keep patterns small and test them on good and bad input, and remember that a regex check in the browser is only for user feedback: the server must validate again.

patterns.jsJavaScript
// A regex literal: /pattern/flags. test() answers yes/no.
const phone = /^(?:\+255|0)([67]\d{8})$/;
for (const raw of ["0712345678", "+255754000111", "0812345678", "071234567"]) {
  const m = raw.match(phone);
  console.log(raw.padEnd(15), m ? "valid -> 0" + m[1] : "invalid");
}

// g flag + matchAll: every match, with capture groups
const text = "Amina scored 88 in Maths, Juma 42 in Maths and Neema 71 in Biology.";
console.log(text.match(/\d+/g));                                   // [ '88', '42', '71' ]

const result = /(?<name>[A-Z][a-z]+)(?: scored)? (?<score>\d+) in (?<subject>\w+)/g;
for (const m of text.matchAll(result)) {
  const { name, score, subject } = m.groups;
  console.log(name, subject, Number(score));
}

// replace: $1-style references, or a function for each match
console.log("Juma   Said ,   Form   4".replace(/\s+/g, " ").replace(" ,", ","));
console.log("0712345678".replace(/(\d{4})(\d{3})(\d{3})/, "$1 $2 $3"));
console.log(text.replace(/\d+/g, (n) => (Number(n) >= 50 ? n : `${n} (fail)`)));

// i = ignore case, \b = word boundary
console.log(/\bexam\b/i.test("Mock EXAM starts Monday"), /\bexam\b/.test("Mock exams start Monday"));

// split on a pattern
console.log("Maths; Biology ,Chemistry;Physics".split(/\s*[;,]\s*/));
Runs in your browser · JavaScript

Key points

  • Anchor validation patterns with ^...$ so the whole string must match.
  • Use the g flag with matchAll and named groups to extract structured data.
  • replace accepts $1 references or a function, and split accepts a pattern.

Exercise

Parse lines like ADM-2026-0001 : Amina Hassan : 88 into objects { adm, year, name, score } using named groups. Reject lines with a badly formatted admission number, scores above 100 or unreadable text, and print why. Then convert every date like 02/11/2026 in a notice to ISO format with replace.

Show solution

Try the exercise yourself first — then compare your approach with this one.

One pattern with named groups reads the three parts of a line and tolerates extra spaces; a second, anchored pattern checks the admission number on its own so the error message can say exactly what is wrong. The date conversion reorders the three groups with $3-$2-$1, and \b stops it matching inside longer numbers.

parse.jsJavaScript
const ADMISSION = /^ADM-(\d{4})-(\d{4})$/;

function parseLine(line) {
  const m = line.match(/^\s*(?<adm>\S+)\s*:\s*(?<name>[A-Za-z' ]+?)\s*:\s*(?<score>\d{1,3})\s*$/);
  if (!m) return { error: `cannot read "${line.trim()}"` };
  const { adm, name, score } = m.groups;
  const parts = adm.match(ADMISSION);
  if (!parts) return { error: `bad admission number ${adm}` };
  if (Number(score) > 100) return { error: `score ${score} is above 100` };
  return { adm, year: Number(parts[1]), name: name.replace(/\s+/g, " "), score: Number(score) };
}

const input = `
ADM-2026-0001 : Amina  Hassan : 88
ADM-2026-0002: Juma Said:42
ADM-26-0003 : Neema Kimaro : 71
ADM-2025-0104 : Ali Mohamed : 105
just some text
`;

const lines = input.split("\n").filter((l) => l.trim() !== "");
for (const r of lines.map(parseLine)) {
  console.log(r.error ? `skip: ${r.error}` : `${r.adm} (${r.year}) ${r.name} ${r.score}`);
}

// Turn 14/03/2026 dates into ISO 2026-03-14 with a replacer
const notice = "Exams run from 02/11/2026 to 20/11/2026; results on 15/12/2026.";
console.log(notice.replace(/\b(\d{2})\/(\d{2})\/(\d{4})\b/g, "$3-$2-$1"));
Runs in your browser · JavaScript

Check your understanding

  1. Why anchor a validation pattern with ^ and $?

  2. What does "a1b22c333".match(/\d+/g) return?

  3. How do you read a named group (?<score>\d+) from a match m?

  4. Is a regex check in the browser enough to keep bad data out of the database?

Ask AI