Before this lesson

Understand groups, alternatives and quantifiers. This lesson distinguishes position assertions from consuming characters.

What you will be able to do

Distinguish line boundaries, dot behavior and assertions that do not consume text.

Understand the mechanism

m changes the line-boundary behavior of ^ and $, not whether dot crosses lines; s changes dot. g requests global matching and i ignores case. These flags solve different problems.

(?=...) checks what can follow without including it in the whole match; (?!...) requires the following pattern to fail. Assertions affect success without consuming characters.

We first extract INFO lines, then digits immediately followed by ms. To reject a few complete reserved words, a format check plus a set is often clearer than many assertions.

Runnable example

const lines = "INFO ready\nERROR stopped\nINFO done";
console.log(JSON.stringify(lines.match(/^INFO .+$/gm)));
console.log(JSON.stringify("12ms 7s 40ms".match(/\d+(?=ms)/g)));
console.log(/a.b/.test("a\nb"), /a.b/s.test("a\nb"));
const id = /^(?!admin$)[a-z]{3,12}$/;
console.log(JSON.stringify(["admin", "administrator", "reader"].map(s => id.test(s))));

Trace and verify

Two INFO lines are returned, and the digit results are 12 and 40. Only the s version crosses a line break. admin is reserved, administrator also fails the 12-character limit, and reader passes.

Common mistakes and boundaries

Do not casually add m to whole-input validation: one matching line can make test return true. Assertions do not fully validate dates, addresses or permissions.

Practice challenge

Allow one optional space before ms while returning only the digits.

Reference solution and reasoning

Use (?= ?ms). 12ms and 12 ms match, while 12 ms does not. The space stays inside the assertion and outside the returned match.

Further reading