Before this lesson

Complete groups, replacement, Unicode and anchors. Understand input-size limits and failure paths.

What you will be able to do

Parse simple logs in stages, retain rejected line numbers and bound input size.

Understand the mechanism

Define the format: LEVEL name=<ASCII identifier> ms=<integer>. LEVEL is INFO or WARN and field order is fixed. This is a custom flat format, not a universal log, JSON or quoted-CSV parser.

The regex checks structure and character ranges; ordinary code checks numeric limits and aggregates. Keep original line numbers before rejecting rows to preserve error locations.

Overlapping nested quantifiers such as (a+)+ can cause catastrophic backtracking in some engines. Prefer bounded, unambiguous patterns, limit input length, and avoid running arbitrary user patterns on the main thread. Lazy quantifiers are not an automatic remedy.

Each row is capped at 120 UTF-16 code units, names at 20 characters and durations at 5 digits, with a semantic maximum of 10000. These are example boundaries, not a complete server abuse-prevention design.

Runnable example

const rows = [
  "INFO name=python ms=25",
  "WARN name=sql ms=40",
  "INFO name=python ms=35",
  "INFO name=java ms=20000",
  "DEBUG name=sql ms=10"
];
const pattern = /^(?<level>INFO|WARN) name=(?<name>[a-z][a-z0-9_-]{0,19}) ms=(?<ms>0|[1-9]\d{0,4})$/;
const totals = new Map(), rejected = [];
rows.forEach((row, index) => {
  const match = row.length <= 120 ? pattern.exec(row) : null;
  if (!match || Number(match.groups.ms) > 10000) {
    rejected.push(index + 1);
    return;
  }
  const {name, ms} = match.groups;
  totals.set(name, (totals.get(name) || 0) + Number(ms));
});
console.log(JSON.stringify([...totals].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)));
console.log(JSON.stringify(rejected));

Trace and verify

python totals 60 and sql totals 40. Row 4 is structurally valid but numerically out of range. Row 5 has an unsupported level. Rejected line numbers are [4,5].

Common mistakes and boundaries

Use proper parsers for nested JSON or HTML. For large logs, consider streaming and accumulator overflow rather than merely widening quantifier limits.

Practice challenge

Add INFO name=java ms=0, INFO name=sql ms=01 and a row longer than 120 characters. Predict the result.

Reference solution and reasoning

java enters the result with total zero. 01 violates the leading-zero rule and the oversized row is rejected before regex execution. Rejected rows become [4,5,7,8], with existing valid totals unchanged.

Further reading