Basic Patterns
Every regex, no matter how intimidating it looks, is built from a small handful of building blocks stacked together. Before the special symbols, there's the simplest case of all: a letter just means that letter. Once that clicks, the two most common special symbols — the dot and the anchors — are easy additions on top.
💡 The Bottom Line
Most characters in a regex match themselves literally. The dot . matches
any single character. The anchors ^ and $ pin a match to the
start and end of the string. Together, these let you tell the difference between "this text
contains a match somewhere" and "this whole string matches, start to finish."
Literal characters
The regex cat matches the three characters "c", "a", "t" in that exact order,
wherever they appear:
/cat/.test("concatenate") // true — "cat" appears inside "concatenate"
/cat/.test("category") // true — "cat" appears at the start
/cat/.test("dog") // false — no "cat" anywhere
Notice that a match doesn't require the whole string to be exactly "cat" — by default, a regex just needs to find its pattern somewhere in the string, unless you tell it otherwise.
The dot: match any single character
A dot . matches any one character (except a newline, by default) — a kind of
wildcard placeholder:
/c.t/.test("cat") // true — "a" fills the dot
/c.t/.test("cot") // true — "o" fills the dot
/c.t/.test("ct") // false — the dot needs exactly one character present
/c.t/.test("caat") // false — two characters between c and t, dot only covers one
⚠️ Watch Out
A literal dot character (like the one in a decimal number or a filename extension) needs to
be escaped as \. — otherwise it's the "match anything" wildcard, not a
literal period. Forgetting this is one of the most common regex mistakes; you'll see it again
in Lesson 6.
Anchors: pinning to start and end
^ means "the match must start here, at the beginning of the string." $
means "the match must end here, at the end of the string." Using both together forces the
entire string to match the pattern, not just some substring of it.
const zip = /^\d{5}$/;
zip.test("90210") // true — exactly 5 digits, nothing before or after
zip.test("90210 ") // false — trailing space means it doesn't end right after the digits
zip.test("A90210") // false — doesn't start right at the digits
zip.test("902100000") // false — more than 5 digits, so $ fails right after the 5th
📋 "Contains a match" vs. "the whole string matches"
- No anchors (e.g.
/cat/) — true if the pattern appears anywhere in the string, even as part of a longer word. - Anchored both ends (e.g.
/^cat$/) — true only if the entire string is exactly that pattern, nothing more, nothing less. - Validation (is this whole input a valid zip code?) almost always wants both anchors. Searching (does this paragraph mention "cat" anywhere?) usually wants no anchors at all.
🙋 There Are No Dumb Questions
Q: If I forget the anchors on a validation regex, what actually goes wrong?
A: Without anchors, /\d{5}/ would happily match a substring inside a longer, invalid
string — "90210-extra-junk" would pass, because it contains five digits
somewhere, even though the whole string clearly isn't a valid zip code. Anchors are what turn a
"search" pattern into a "validate the whole thing" pattern.
🔧 Try It Yourself
In a console, compare /^\d{5}$/.test("90210x") to /\d{5}/.test("90210x").
One returns false, the other true — work out why before running it,
then confirm.
✅ Quick Check
What does the pattern /^abc$/ require that /abc/ does not?
Next up: character classes and quantifiers — how to match "any digit" or "any letter" and say how many times something should repeat.