Regular expressions have a reputation for looking like line noise — a string of punctuation that somehow finds phone numbers in a wall of text. Once you know the dozen or so building blocks, though, most patterns you'll actually write in day-to-day work are readable at a glance. This is the beginner-level tour of those building blocks.
What a regex actually is
A regular expression ("regex" for short) is a pattern that describes a set of strings. You use it to answer three kinds of questions: does this string match the pattern (validation), where does the pattern occur in this text (search), and what parts of the match do I want to pull out (extraction). Every mainstream programming language ships a regex engine, and JavaScript's — the one your browser and Node.js both use — is what powers the examples below.
Literal characters
The simplest regex is just the text you're looking for. The pattern cat matches the three characters "c", "a", "t" in that order, anywhere in the string — so it matches "cat", but also the middle of "concatenate". Everything else in this guide is about controlling where and how much it can match.
Character classes
A character class matches one character from a set, rather than one specific character.
\d— any digit (0-9).\Dis the opposite: any non-digit.\w— any "word" character (letters, digits, underscore).\Wis the opposite.\s— any whitespace (space, tab, newline).\Sis the opposite..— any character except a line break.[abc]— a custom set: matches "a", "b", or "c".[^abc]negates it — anything except those three.[a-z]— a range inside a custom set: any lowercase letter.
Anchors
Anchors don't match characters — they match positions.
^— start of the string (or start of a line, with themflag).$— end of the string (or end of a line, with themflag).\b— a word boundary, the position between a word character and a non-word character. Handy for matching whole words:\bcat\bmatches "cat" but not the "cat" inside "concatenate".
Forgetting anchors is one of the most common beginner surprises: \d{3} matches three digits anywhere in the string, so it'll happily match the first three digits of a ten-digit number. If you mean "the entire string is exactly three digits," you need ^\d{3}$.
Quantifiers
A quantifier says how many times the thing right before it can repeat.
*— zero or more times.+— one or more times.?— zero or one time (optional).{3}— exactly 3 times.{2,4}— between 2 and 4 times.{2,}— 2 or more times.
Quantifiers are greedy by default — they match as much as possible before backtracking. Add a ? right after one to make it lazy instead, matching as little as possible: given <b>bold</b> and <b>more</b>, the greedy pattern <b>.*</b> matches the whole thing from the first <b> to the last </b>, while the lazy <b>.*?</b> stops at the first </b> it finds.
Groups and alternation
Parentheses ( ) group part of a pattern together — so a quantifier can apply to the whole group instead of just the last character — and capture whatever matched inside them so you can extract it afterward. (?:...) groups without capturing, which is useful when you need the grouping but don't care about extracting that part. The pipe | means "or": cat|dog matches either word.
Named groups — (?<year>\d{4}) — work the same way but let you read the result back by name (match.groups.year) instead of by position, which keeps patterns with several captures readable.
Reading a real pattern
Put it together and a pattern like a US-style phone number stops looking like noise:
^\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$^/$— anchor the match to the whole string.\(?— an optional literal((escaped, since(is normally special).\d{3}— three digits (the area code).\)?— an optional literal).[-.\s]?— an optional separator: a dash, a dot, or whitespace.\d{3}, another separator, then\d{4}— the rest of the number.
That reads as one sentence once you know the vocabulary, not a wall of symbols.
Mistakes worth avoiding early
- Forgetting to escape special characters. Characters like
. * + ? ( ) [ ] { } ^ $ |and\all have special meaning. To match a literal dot in a domain name, you need\.— an unescaped.matches any character, soexample.comwould also match "examplexcom". - Leaving out anchors when you mean to validate an entire string, not just find a substring somewhere inside it.
- Not testing edge cases. Empty strings, extra whitespace, and unexpected Unicode characters break naive patterns constantly — always test against a few real examples, not just the happy path.
- Reaching for regex to parse HTML or deeply nested structures. Regex is great at flat, regular text — it's the wrong tool for anything with arbitrary nesting. Use a real parser for that.
Try it yourself
If you're still getting comfortable with the syntax, the Regex Builder lets you click together character classes, quantifiers, and groups instead of typing them from memory — a good way to build intuition for what each piece actually does. Once you're writing patterns directly, the Regex Tester gives you live match highlighting and capture group output as you type. Both run entirely in your browser.