Before this lesson

Know JavaScript strings, arrays and functions. Use a modern browser console or save lesson.js and run it with Node.js. Run each chapter independently.

What you will be able to do

Distinguish literal strings from patterns and build testable input rules.

Understand the mechanism

A regular expression describes a character-sequence pattern. test reports whether a match exists; exec returns the first match and its position. Searching for digits and requiring an entire input to consist of digits are different tasks.

A /pattern/ literal suits a fixed source-code rule. new RegExp receives a string, introducing both string escaping and regex escaping. To pass backslash-d to the constructor, write "\\d" in the source string.

Here an ID is HS- followed by four ASCII digits. Without m, ^ and $ constrain input boundaries. A dot normally matches one non-line-terminator character; escape it for a literal dot. Define the requirement before translating it into a pattern.

Runnable example

const search = /\d+/;
const whole = /^HS-\d{4}$/;
const constructed = new RegExp("^HS-\\d{4}$");
console.log(JSON.stringify(["HS-0042", "xHS-0042", "HS-42", "HS-0042\n"].map(s => whole.test(s))));
console.log(search.exec("part 42 ready")[0]);
console.log(constructed.test("HS-0042"));
console.log(/file\.js/.test("fileXjs"));

Trace and verify

Only the first of the four inputs passes. The search extracts 42. The constructor agrees with the literal, and an escaped dot does not accept X.

Common mistakes and boundaries

This course uses the JavaScript regex dialect. Boundaries, flags and replacement syntax differ across languages. For a fixed substring, includes is often clearer.

Practice challenge

Require AB- followed by three digits and test AB-000, AB-1234 and an empty string.

Reference solution and reasoning

Use /^AB-\d{3}$/ for true, false, false. Omit g because this is validation rather than an iterative search.

Lab: finding a match is not validating the whole input

The contract is exactly HS- followed by four ASCII digits, with no surrounding whitespace. Finding a valid-looking fragment is not whole-field validation. In JavaScript, m changes anchors to line boundaries. Compare substring search, multiline matching and whole-input matching without m.

Run this separate experiment in a modern browser Console; it is not a replacement for the main example above.

const loose = /HS-[0-9]{4}/;
const familiar = /^HS-[0-9]{4}$/m;
const exact = /^HS-[0-9]{4}(?![\s\S])/;
for (const input of ['HS-1234', 'xHS-1234', 'HS-1234\n', 'HS-1234']) {
  console.log(JSON.stringify(input), loose.test(input), familiar.test(input), exact.test(input));
}
console.assert(exact.test('HS-1234'));
console.assert(!exact.test('HS-1234\n'));

Expected observations

The Boolean triples are true/true/true, true/false/false, true/true/false and false/false/false. The terminal newline is an intentional counterexample.

Why this happens and where it stops applying

The exact pattern has no m flag. The start anchor requires the beginning, and (?![\s\S]) requires that no character follows. Another explicit strategy checks that a match starts at index zero and consumes the full input length. Trimming first changes the acceptance policy; do it only if surrounding whitespace is intentionally allowed. Likewise, an ASCII identifier should not accidentally accept every Unicode digit category.

Extension challenge

Change the rule to exactly six digits and choose at least five boundary inputs.

Reasoned solution

Test empty input, five/six/seven digits, a terminal newline and full-width digits. Use /^[0-9]{6}(?![\s\S])/ without g, which would add lastIndex state to repeated tests. Rerun the fixtures when moving to another regex engine or API.

Further reading