← back to blog
reference 10 min read May 2026

Essential Regex Patterns Every Developer Should Know

Regular expressions show up everywhere in software development — input validation, log parsing, data transformation, search and replace, routing. Knowing the core syntax cold and having a library of reliable patterns for common tasks eliminates a significant amount of boilerplate lookup time and prevents the subtle bugs that come from writing a regex under pressure.

Core syntax reference

Character classes

PatternMatches
.Any character except newline
\dDigit (0–9)
\DNon-digit
\wWord character: [a-zA-Z0-9_]
\WNon-word character
\sWhitespace: space, tab, newline, carriage return
\SNon-whitespace
[abc]Any of: a, b, or c
[^abc]Anything except a, b, or c
[a-z]Any lowercase letter
[a-zA-Z0-9]Any alphanumeric character

Quantifiers

PatternMeaning
*Zero or more (greedy)
+One or more (greedy)
?Zero or one
{n}Exactly n times
{n,}n or more times
{n,m}Between n and m times
*?Zero or more (lazy — matches as few as possible)
+?One or more (lazy)

Anchors and boundaries

PatternMeaning
^Start of string (or start of line with m flag)
$End of string (or end of line with m flag)
\bWord boundary (between \w and \W)
\BNot a word boundary

Groups and alternation

PatternMeaning
(abc)Capturing group
(?:abc)Non-capturing group (faster, no capture overhead)
(?<name>abc)Named capturing group
a|bAlternation: a or b
(?=abc)Positive lookahead: followed by abc
(?!abc)Negative lookahead: not followed by abc
(?<=abc)Positive lookbehind: preceded by abc
(?<!abc)Negative lookbehind: not preceded by abc

Flags

FlagEffect
gGlobal — find all matches, not just the first
iCase-insensitive
mMultiline — ^ and $ match start/end of each line
sDotall — . matches newline characters too

Greedy vs lazy matching

By default, quantifiers are greedy — they match as much as possible. This is a frequent source of bugs when extracting content from HTML or structured text.

const html = "<b>bold</b> and <b>more bold</b>"; // Greedy — matches everything from first <b> to last </b> html.match(/<b>.+<\/b>/)[0] // → "<b>bold</b> and <b>more bold</b>" // Lazy — matches each <b>...</b> individually html.match(/<b>.+?<\/b>/g) // → ["<b>bold</b>", "<b>more bold</b>"]

Adding ? after a quantifier makes it lazy — it matches as few characters as possible while still satisfying the overall pattern.

Practical patterns

Email address (pragmatic)
/^[^\s@]+@[^\s@]+\.[^\s@]+$/
Validates the basic structure: local part, @, domain, dot, TLD. Doesn't try to implement the full RFC 5321 spec (which would be hundreds of characters long). For production, send a confirmation email — regex can't verify deliverability.
URL (http and https)
/^https?:\/\/[^\s/$.?#].[^\s]*$/i
Matches http:// or https:// followed by a valid-looking domain and optional path. The i flag makes scheme matching case-insensitive. Doesn't validate TLDs or IP addresses specifically.
IPv4 address
/^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/
Validates each octet: 0–255. The groups 25[0-5], 2[0-4]\d, and [01]?\d\d? together cover all valid values without allowing numbers above 255.
Date (YYYY-MM-DD)
/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/
Validates ISO 8601 date format with range checking on month (01–12) and day (01–31). Doesn't validate day-month combinations (e.g., Feb 31) — use a date library for that.
Strong password
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*]).{12,}$/
Requires: at least one lowercase letter, one uppercase letter, one digit, one special character, and minimum 12 characters total. Uses lookaheads to check for each required character type without specifying order.
Hex color code
/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
Matches both 6-digit (#ff5733) and 3-digit (#f57) hex color codes. The alternation checks 6 characters first, then 3, with a required leading #.
Semantic version (semver)
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([\da-zA-Z-]+(?:\.[\da-zA-Z-]+)*))?(?:\+([\da-zA-Z-]+(?:\.[\da-zA-Z-]+)*))?$/
Full semver validation including optional pre-release labels (1.0.0-alpha.1) and build metadata (1.0.0+build.123). Each version component prevents leading zeros (e.g., 01.0.0 is invalid semver).
Credit card number (structural)
/^[\d\s-]{13,19}$/
Checks that the string contains only digits, spaces, and hyphens, with a total length between 13 and 19 characters. For real validation, use the Luhn algorithm after cleaning the input — regex can't verify checksum validity.
Slug (URL-friendly string)
/^[a-z0-9]+(?:-[a-z0-9]+)*$/
Validates a slug: lowercase alphanumeric characters separated by single hyphens, no leading or trailing hyphens. Use this to validate slugs before storing or routing to them.
Extract JSON values by key
/"key"\s*:\s*"([^"]*)"/
Extracts a string value from JSON by key name. Replace "key" with the actual key. Capture group 1 contains the value. Fragile for nested or escaped values — use a proper JSON parser for production code.

Common mistakes

Not anchoring validation patterns

Without ^ and $, a pattern matches anywhere in the string. The pattern /\d+/ matches "abc123def" because there are digits somewhere in it.

// Wrong — matches any string containing digits /\d+/.test("abc123") // true — matches "123" inside // Correct — entire string must be digits /^\d+$/.test("abc123") // false /^\d+$/.test("123") // true

Catastrophic backtracking

Certain regex patterns can cause exponential worst-case matching time. Nested quantifiers on overlapping character classes are the most common culprit: /(a+)+/ on a long string of a's followed by a non-matching character can take seconds or minutes.

ReDoS vulnerability: If you apply user-provided regex patterns to user-provided strings, catastrophic backtracking becomes a denial-of-service vector. Always validate regex patterns from untrusted sources or use a safe regex library with backtracking limits.

Special characters not escaped

These characters have special meaning in regex and must be escaped with \ if you want to match them literally: . * + ? ^ $ { } [ ] | ( ) \. Forgetting to escape a dot is extremely common — /example.com/ matches "exampleXcom" because . means any character.

Escaping utility: To build a regex that literally matches a string, escape all special characters: str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'). This is useful when building dynamic patterns from user input.