You’ve learned the individual pieces — literals, classes, quantifiers, groups, anchors, lookaround, flags. Now it’s time to combine them into complete patterns that solve problems you’ll actually run into. Each example below builds up from a plain-English requirement to a working regex.
Extracting hashtags from a tweet
Requirement: pull out every #word from a piece of social text.
A hashtag starts with # followed by one or more “word” characters — letters, digits, or underscores, which is exactly what \w covers.
const tweet = "Loving the #JavaScript and #regex tutorials, #LearnToCode!";
tweet.match(/#\w+/g);
// ["#JavaScript", "#regex", "#LearnToCode"]
The g flag is what makes .match() return every hashtag instead of stopping at the first one. Notice the pattern doesn’t require a space or start-of-string before the # — it just needs \w+ to follow it, which is enough for typical text.
Validating a simple slug
Requirement: confirm a string is a URL-safe slug — lowercase letters, digits, and single hyphens between words, like hello-world-2024.
const slugPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
slugPattern.test("hello-world-2024"); // true
slugPattern.test("Hello-World"); // false — uppercase not allowed
slugPattern.test("hello--world"); // false — double hyphen breaks the pattern
Breaking this down: [a-z0-9]+ matches one chunk of lowercase alphanumerics, and (?:-[a-z0-9]+)* repeats “a hyphen followed by another chunk” zero or more times. The non-capturing group (?:...) groups the repeated unit without creating a capture you don’t need. The anchors ^ and $ make sure the entire string matches this shape — without them, "Hello-World" would still partially match the lowercase portion, which isn’t what a validator should report.
Extracting key=value pairs from a query string
Requirement: turn name=Ada&lang=en&debug=true into structured key/value pairs.
const qs = "name=Ada&lang=en&debug=true";
const pairs = [...qs.matchAll(/(\w+)=(\w+)/g)].map((m) => [m[1], m[2]]);
// [["name", "Ada"], ["lang", "en"], ["debug", "true"]]
Here two capture groups do the real work: group 1 grabs everything before the =, group 2 grabs everything after it, and \w+ conveniently stops at the = and & characters since neither is a word character. matchAll (paired with the g flag) returns an iterator of every match with its groups, which is why spreading it into an array and mapping over m[1]/m[2] gives you clean pairs.
Redacting credit card digits with replace
Requirement: replace all but the last four digits of a card number with asterisks before logging it.
const cc = "Card on file: 4111 1111 1111 1234";
cc.replace(/\b(\d{4}) (\d{4}) (\d{4}) (\d{4})\b/, "**** **** **** $4");
// "Card on file: **** **** **** 1234"
This one leans on \b (word boundary) to make sure we’re matching a clean run of digit groups, and four capture groups — one per block of four digits. In the replacement string, $4 refers back to the fourth captured group, so only the last block survives; the rest is replaced with literal asterisks. This is a common real pattern for scrubbing sensitive data out of logs before they’re written to disk.
Tip
Notice a theme across all four examples: anchors (^/$) when you need to validate a whole string, no anchors when you’re extracting matches from inside a larger text, and non-capturing groups ((?:...)) whenever you need repetition but don’t need the matched text back.
Try it yourself
Modify the query-string demo’s pattern to ([\w-]+)=([\w-]+) and add a hyphenated value to the test text, like theme=dark-mode. Predict whether the original pattern or the new one handles it correctly.
What should happen
The original (\w+)=(\w+) stops at the hyphen, because - isn’t a word character — so theme=dark-mode would only capture dark as the value, silently truncating it. Adding - inside the character class ([\w-]+) lets both key and value include hyphens, correctly capturing dark-mode in full. This is a good example of how a pattern that “basically works” can quietly produce wrong results on inputs you didn’t test.
What’s next
Real patterns like these can go wrong in a different way too — not producing the wrong answer, but taking forever to produce any answer. The next lesson covers performance: how backtracking can spiral out of control, and how to write patterns that stay fast.