Write a regex and explain it
Edge cases and counter-examples served with it
Write me a regex that matches [describe the requirement]. Requirements: 1) give the expression; 2) explain each piece; 3) give 3 examples that should match and 3 that should not; 4) say which extreme input would make this expression backtrack catastrophically, and how to avoid it.
How to use
Paste the three should-not-match examples back in and run them. That is where the expression usually turns out to be too greedy.
Good for
- Validating input with a written spec (order ids, log lines, device numbers in a fixed format) where the boundaries can be enumerated.
- Extracting fields from a log volume too large to check by eye.
Not for
- Parsing JSON, HTML or anything nested: use a parser; a regex collapses at the first level of nesting.
- The input format itself is undefined (free-text addresses): define the format first, or the regex just turns ambiguity into errors.
Example
Input
Requirement: match mainland China mobile numbers; allow a +86 or 86 prefix; allow spaces or hyphens as separators inside the number; nothing else. Samples: +86 138 0013 8000, 13800138000, 8613800138000, 12800138000 (reject), +86 138-0013-8000
What you get
Recommend two steps, normalize then validate: strip the prefix and separators, then match `^1[3-9]\d{9}$`, rather than folding separators into one giant regex. Then walk each piece, give 3 matches and 3 rejects, and note that a `(\d+)+` style construct backtracks catastrophically on a long digit string while fixed-length quantifiers avoid it.Common mistakes
- Using a regex to parse HTML or nested JSON: it breaks at one level of nesting and can report half a document as a match.
- Testing only the strings that should match and never the ones that should not, so `.*` looks like it works.
Try tweaking it like this
- Add 'give the equivalent without backtracking (RE2 or atomic groups)' to keep one malicious log line from pinning a CPU.
- Add 'list what this regex explicitly does not support' so you do not assume full coverage.