1. Home
  2. Guides
  3. Twelve Regular Expressions Worth Knowing by Heart

Twelve regular expressions you will end up using every week

Most regexes in a codebase are the same handful of patterns written badly. Here are the ones worth having ready, with the parts that usually cause the bug.

By Enrique M. · 8 min read · Last reviewed 2026-10-13

Email: only as good as your validation layer

No regular expression validates an email address properly, because the rules for the local part are defined by RFC 5321 and permit almost anything. A pattern that rejects a valid address costs you a sign-up; a pattern that accepts an invalid one costs you a bounce.

What a pattern is good for is finding obvious mistakes in a form before submission, and extracting a candidate address out of a blob of text. Anything beyond that belongs in a verification email.

^[^\s@]+@[^\s@]+\.[^\s@]{2,}$

URL: prefer the URL parser

A URL is specified in RFC 3986 and the grammar has more corners than any pattern covers, including IPv6 hosts, userinfo, percent-encoding and empty path segments. The `URL` constructor in every modern runtime implements it correctly.

Reach for a regular expression only when you are extracting URLs out of free text, where you are pattern-matching a shape rather than validating a URL. For validation, always use the parser.

const parsed = new URL(input);

Dates: do not match dates with a regex

A pattern can check the shape of a date, not whether it exists. The pattern `[0-9]{4}-[0-9]{2}-[0-9]{2}` happily accepts 2026-02-31, and no amount of regex can fix that without becoming a calendar.

Match the shape if you need to find candidate dates in text, then hand the value to a date parser and check that it round-trips.

const d = new Date(value);
const valid = !isNaN(d.getTime()) && d.toISOString().slice(0, 10) === value;

Named groups make the code readable

A pattern with six numbered groups is unreadable in a stack trace and impossible to maintain. Named groups give the match a vocabulary, and the same name works in the replacement string.

const re = /(?\d{4})-(?\d{2})-(?\d{2})/;
const { year, month, day } = re.exec(value).groups;

The catastrophic backtracking trap

A pattern with two quantifiers nested inside each other can require exponential time on an input that does not match. The classic shape is a repeated group containing a repeated character, such as `(a+)+b`.

Against a long string of a characters with no trailing b, the engine tries every possible way to split the input and never finishes. If a validation endpoint can receive a 10 KB body, that is a denial of service with a valid-looking request.

  • Avoid nesting quantifiers: `(a+)+` is the shape to watch for.
  • Prefer a possessive-style rewrite: `a+b` or an atomic group where the engine supports it.
  • Bound the input length before matching, not after.
  • If a pattern hangs in the tester, nested quantifiers are the first thing to check.

What to take away

  • Validate URLs with `new URL()`, and dates with a date parser, not a pattern.
  • Use named capture groups so the code reads like the intent.
  • Never nest quantifiers, and bound the input length before matching.
  • A regex that matches a shape is not a validator.

Related tools