Anchors and groups: where, and which part
Anchors tie a pattern to a position; groups decide what you get back.
Anchors match a position, not a character
^ means the start and $ means the end. They consume nothing — they assert that you are at a position. That is why ^$ matches an empty string: two assertions and nothing between them.
By default these mean the start and end of the whole subject. With the m flag they mean the start and end of each line, which is usually what you want when processing a file and rarely what you want when validating a single value.
That distinction has a security edge in JavaScript. Validating with /^[a-z]+$/ on a value containing a newline behaves differently from what many people expect: $ can match before a trailing newline, so "abc\n" passes. When a value must be exactly one line, check for the newline separately or anchor with \A and \z in languages that have them.
Word boundaries
\b matches the position between a \w character and something that is not one. It is how you ask for a whole word: \bcat\b matches the cat in "the cat sat" and not the one in "concatenate".
Because \b is defined in terms of \w, it inherits \w's limits. \bcafé\b does not behave as you would hope, since é is not a word character — the boundary lands in the middle of the word.
Groups: capturing, non-capturing, and named
Parentheses do two jobs at once. They group part of a pattern so a quantifier or alternation applies to all of it, and they capture what that part matched so you can use it afterwards.
When you only need the grouping, (?:…) groups without capturing. This keeps your capture numbers stable, which matters because a group added in the middle of a pattern silently renumbers everything after it — a real source of bugs in code that refers to match[2].
Named groups avoid that entirely: (?<year>\d{4}) is referred to by name rather than position, in both the match result and the replacement string. Where a language supports them, they are almost always the better choice, because the name says what the group is for and a reader does not have to count brackets.
Alternation with | is lower precedence than almost everything, so ^cat|dog$ means "starts with cat, or ends with dog" — very likely not what was meant. ^(cat|dog)$ is the pattern that matches either word exactly.
Worked examples
Match a whole word only
/\bcat\b/gAgainst:
the cat sat, concatenate, cat.Two matches: the standalone cat and the one before the full stop. The one inside concatenate is skipped.
See how alternation binds
/^cat|dog$/gmAgainst:
cat food hot dog catalogueIt matches the cat at the start of two lines and the dog at the end of one — not whole words. ^(cat|dog)$ is the stricter version.
Pull a year out by name
/(?<year>\d{4})-(?<month>\d{2})/gAgainst:
Released 2026-09 and 2025-01Named groups survive edits to the pattern; numbered ones renumber the moment you add a bracket earlier on.
Check yourself
Practice questions written for this lesson — not past exam papers.
Practise every question in this subject
What does ^ match?
Why prefer (?:…) over (…) when you only need grouping?