Anchors & Alternation
You wrote cat to find the animal and your search lit up category, scatter, and bobcat too. The pattern matched a run of letters anywhere it could sit, because nothing told it where to stand.
- ▸
^and$match a position, not a character. A match against them advances the cursor by zero. - ▸
a|abrun againstabmatchesa, not the longerab: the first branch that works wins. - ▸
^cat|dog$does not mean a string that is exactlycatordog. The bar reaches farther than the eye expects.
Every piece of a pattern so far has eaten a character: a literal takes one, a class takes one, the dot takes one. ^ and $ take none. They mark a position. ^ is the spot just before the first character of the input; $ is the spot just after the last. A match against either lands on that seam between characters and the cursor advances by zero.
Run cat on its own against a cat sat. The engine slides along and finds cat sitting in the middle, a match. Now write ^cat. The engine asks one extra question first: am I standing at the very start of the input? At position 0 the answer is yes but the next character is a, not c, so it fails, and because ^ only ever holds at the start, there is nowhere else to retry. ^cat matches cat dozes and rejects a cat sat.
$ does the mirror job at the tail. cat$ matches only when cat runs right up to the end, so a black cat matches and cat nap does not. One subtlety worth holding: in most engines $ also accepts the position just before a single trailing newline, so a line read from a file still matches even with the \n still attached. Put both on and ^cat$ demands the entire input be exactly cat, start pinned, end pinned, nothing else allowed in between.