Without anchors, a validation pattern accepts any string that merely contains a valid part.
Anchors match a position, not a character, so they consume no text:
^start of the string (or of each line in multiline mode).$end of the string (or of each line in multiline mode). In Python and PCRE$also matches just before a final newline; in JavaScript it doesn't.\ba word boundary: between a word character (\w) and a non-word character or the string edge.\bcat\bfindscatbut notconcatenate.\Bis the opposite.\Aand\z(Python:\Aand\Z) always mean the very start and very end of the string, regardless of flags.
Anchors are essential for validation. \d{5} finds five digits inside "abc123456", so it would accept that string as a ZIP code; ^\d{5}$ requires the whole string to be five digits. In Python re.fullmatch(r"\d{5}", s) does the same without anchors and avoids the trailing-newline subtlety of $.
Word boundaries depend on what counts as \w, so \b treats - and ' as boundaries: \bcan\b matches inside can't.
Example
import re
print(re.findall(r"cat", "cat concatenate")) # ['cat', 'cat']
print(re.findall(r"\bcat\b", "cat concatenate")) # ['cat']
zip_re = re.compile(r"^\d{5}$")
print(bool(re.search(r"\d{5}", "abc123456"))) # True (contains five digits)
print(bool(zip_re.search("abc123456"))) # False
print(bool(zip_re.search("12345"))) # True
print(bool(zip_re.search("12345\n"))) # True! $ allows a final newline
print(bool(re.fullmatch(r"\d{5}", "12345\n"))) # False
lines = "error: a\nok\nerror: b"
print(re.findall(r"^error: (\w)", lines, re.MULTILINE)) # ['a', 'b']Remember
- ^ and $ anchor to the start and end; \b to word edges
- Validation patterns must be anchored (or use fullmatch)
- In Python and PCRE, $ also matches before a final newline
Watch out for
- Validating input with an unanchored pattern, which accepts anything that contains a valid substring.