Basis Lab

Describing a Pattern in Text

Writing a Pattern That Holds Up, and Knowing What It Will Cost

Last timeWhich Match You Actually Get

A date pattern built from nothing against a fixed list of eight strings, one change per failing string, ending with the two numbers that price it: the paths through it and the length of the input.

You want to accept a date written as four digits, a dash, two digits, a dash,

two digits. Writing something that matches 2026-11-06 takes a few seconds.

Knowing that you are finished takes longer, and knowing what the thing will do

when somebody pastes forty characters of nonsense into the field is a separate

question again. Both have answers, and both come from the same two habits:

decide in advance which strings the pattern has to judge, and count the paths

through it once it is written.

Start from the strings, not from the pattern

Here is the list. Eight strings, one of them accepted and seven rejected, each

rejected for a different reason.

FIG 1Eight strings, and the version that first gets each one right
stepinputwantedfirst right atwhat that version addedwhat happened
12026-11-06acceptV1digits and literal dashes in the right orderThe only string on the list that must come out accepted, and the only one an example-driven pattern would ever have been tested against.
22026/11/06rejectV1nothing, the dashes were already literalFree. A dash written as itself only matches a dash, so the first attempt already refuses this.
32026-1-6rejectV2exact counts, four digits then two then twoThe first real change. A repetition of one or more digits accepts a single digit, and a month written as 1 is the sort of thing a form sends.
412026-11-06rejectV3a start anchorA search finds the date inside the longer string. No accepted example ever asks for this, which is why it is the change people omit.
52026-11-06 okrejectV3an end anchorThe same omission at the other end. Trailing rubbish after a valid date is the classic way a parser accepts a line it should have rejected.
62026-11-06 and a newlinerejectV4a whole-input match instead of an anchored searchThe end anchor is satisfied just before a newline that ends the input, so V3 accepts this and reports a match ten characters long against an eleven character value.
72026-13-45rejectV5named ranges for the month and the dayCorrect shape, impossible numbers. Two digits accepts every number from 00 to 99, and only a choice between cases narrows it.
82026-02-30rejectV6a calendar check in the code after the patternThe only one on the list that shape cannot settle, because whether 30 is a legal day depends on the month beside it.
8 steps
The right-hand column is the whole method. Each version differs from the one before it by one change, and that change exists because of the string on its row. Read downwards and the pattern grows; read the column upwards from any row and you can say why every piece of the finished pattern is there.

The order matters more than it looks. Building towards a list means the pattern

grows by changes that something forced, which gives every piece of it a reason

a reviewer can ask for and get. Building from examples you expect to accept

gives you a pattern that accepts those examples and an unbounded number of

other things, because no string you want accepted will ever ask you for an

anchor, and none will ever ask you for a bound.

The lesson stops here

9 more paragraphs to go

You have read the opening. The rest of the argument, the problems that check whether it landed, and the lines worth keeping at the end all come with a plan.

The first lesson of every course in the library reads the whole way through, free, so you can see exactly what the rest of them are.

See the planThe contents

This is the reading half

Starting the course gives you your own copy of it. Every idea on every page has problems standing under it, marked with a reason rather than a tick, and any sentence you do not believe can be opened and argued with. None of that can happen on a page nobody owns.

The contents

The rest of this course

  1. 01The Set of Strings a Pattern Accepts, and the Three Operations That Build It
  2. 02Building by Hand the Machine a Pattern Turns Intoopening only
  3. 03Following Every Path at Once, So Nothing Ever Has to Be Undoneopening only
  4. 04Collapsing a Set of States Into One Lookup Table, and What That Table Can Costopening only
  5. 05Why a Short Pattern Takes Thirty Seconds on One Lineopening only
  6. 06Back References, Look Around and Why Brackets Cannot Be Matchedopening only
  7. 07Which Match You Actually Get, and Why Two Engines Disagreeopening only
  8. 08Writing a Pattern That Holds Up, and Knowing What It Will Costyou are here

Read alongside