Don't like ads? Go Ad-Free Today

The Developer’s Regex Cheat Sheet Patterns Worth Memorizing

Published on
The Developer's Regex Cheat Sheet: Patterns Worth Memorizing 1
ADVERTISEMENT · REMOVE?

Regex is one of those skills that pays dividends across every language you’ll ever write. The same pattern that validates an email in Python strips query strings in Go and sanitizes form input in JavaScript. Learn it once, use it everywhere.

This isn’t a syntax primer. It’s the patterns you actually reach for in real projects — the ones that show up in form validators, log parsers, URL routers, and data pipelines. The table below is the core of it. The prose around it covers where people get burned.

The Patterns Worth Keeping

These 11 patterns cover the scenarios that come up repeatedly in production code. Use the Regex Tester to validate them against your own inputs before wiring them in.

PatternWhat It MatchesExample MatchNotes
^[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}$Email addressuser@example.comPermissive by design — true RFC 5322 is a rabbit hole. Anchor with ^$.
https?:\/\/[\w\-._~:/?#[\]@!$&'()*+,;=%]+HTTP/HTTPS URLhttps://example.com/path?q=1Doesn’t validate structure — just confirms it looks like a URL.
^(\d{1,3}\.){3}\d{1,3}$IPv4 address (format only)192.168.1.1Matches 999.999.999.999 — validate range in code, not regex.
^(\+\d{1,3}[\s-])?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$North American phone number(555) 867-5309Handles common delimiters. International formats vary too much for one pattern.
[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}UUID v4550e8400-e29b-41d4-a716-446655440000Case-insensitive — use i flag or add A-F to character classes.
^[a-z0-9]+(?:-[a-z0-9]+)*$URL slugmy-article-titleNo leading/trailing hyphens, no consecutive hyphens.
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$ISO 8601 date (YYYY-MM-DD)2026-04-10Validates format and range, not calendar validity (Feb 31 passes).
^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$CSS hex color#ff6600 or #f60Both 3- and 6-digit shorthand. Add {8} for 8-digit RGBA hex.
^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([\w.-]+))?(?:\+([\w.-]+))?$Semantic version string1.2.3-beta.1+build.42Captures pre-release and build metadata as optional groups.
\b(?:\d{4}[\s-]?){3}\d{4}\bCredit card number (mask, not validate)4111 1111 1111 1111Use for masking in logs, not validation. Luhn check requires code.
\s+Whitespace runs"hello world""hello world"Replace with a single space for whitespace normalization.

Where Patterns Break in Practice

Greedy vs. Lazy Matching

Quantifiers like * and + are greedy by default — they consume as much as possible. This bites you when extracting content between delimiters. <.+> on <b>bold</b> matches the entire string, not <b>. Switch to lazy with .+? to stop at the first closing delimiter instead of the last.

Anchoring: When ^ and $ Aren’t Enough

Without anchors, a pattern can match anywhere in a string. \d+ matches abc123def — it finds the digits in the middle. For full-string validation, wrap patterns in ^...$. In multiline mode (m flag), ^ and $ match line boundaries, not the full string boundaries. If you’re validating a single value (an email, a UUID), set the m flag intentionally, not by habit.

The Multiline Flag Pitfall

The m flag changes what ^ and $ mean. The s (dotAll) flag changes what . matches — without it, . doesn’t match newline characters. Parsing multi-line log entries with .+? You need s or [\s\S]+ as a fallback for engines that don’t support dotAll.

Testing Before Wiring In

Don’t drop a regex into an application and test it against one happy-path input. Patterns fail on edge cases: unicode characters, empty strings, leading/trailing whitespace, inputs that are almost-but-not-quite valid. The IO Tools Regex Tester lets you run a pattern against multiple test strings simultaneously, so you can check the valid cases and the invalid ones side by side before the code ships. The Regex Cheatsheet tool is useful when you’re in the middle of building a pattern and need a quick syntax reference without leaving your browser.

When testing, build a matrix: what should match, what definitely should not, and what’s on the boundary. An email validator that accepts user@ or rejects user+tag@example.co.uk is worse than no validator at all.

Language Quirks Worth Knowing

The patterns in the table above are broadly portable, but the engine matters at the edges.

  • JavaScript uses the ECMA regex engine. Named capture groups ((?<name>...)) are supported in ES2018+. The v flag (introduced in ES2024) adds set notation and Unicode property escapes. Lookaheads work; lookbehinds are ES2018+ and have variable-length restrictions in some older V8 versions.
  • Python uses the re module (PCRE-adjacent but not identical). The re.compile() pattern is worth using — compiled patterns are faster when called repeatedly in loops. One subtle difference: Python’s \b word boundary is Unicode-aware by default, so it works on non-ASCII word characters. JavaScript’s \b is ASCII-only unless you use the u or v flag.
  • Go uses RE2 syntax, which deliberately excludes backreferences and lookaheads. This is a security decision — RE2 guarantees linear-time matching, which prevents catastrophic backtracking. If you’re porting a pattern from Python or JS to Go and it uses lookaheads or backreferences, you’ll need to restructure the logic.

Real-World Example: Email Validation Across Languages

Same pattern, two implementations — a JS form validator and a Python input check:

// JavaScript — client-side form validation
const EMAIL_RE = /^[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}$/;

function validateEmail(input) {
  const value = input.trim();
  if (!EMAIL_RE.test(value)) {
    throw new Error(`Invalid email address: ${value}`);
  }
  return value;
}

// Usage
document.querySelector('#signup-form').addEventListener('submit', (e) => {
  e.preventDefault();
  try {
    const email = validateEmail(e.target.email.value);
    submitForm({ email });
  } catch (err) {
    showError(err.message);
  }
});
# Python — API request validation
import re

EMAIL_RE = re.compile(r'^[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}$')

def validate_email(value: str) -> str:
    value = value.strip()
    if not EMAIL_RE.match(value):
        raise ValueError(f"Invalid email address: {value!r}")
    return value

# Usage in a Flask route
@app.route('/signup', methods=['POST'])
def signup():
    try:
        email = validate_email(request.json.get('email', ''))
    except ValueError as e:
        return jsonify({'error': str(e)}), 400
    # continue with valid email...

Both use the same underlying pattern. The only meaningful difference: Python’s re.compile() pre-compiles the pattern so repeated calls don’t reparse it on every invocation — worth doing in any hot path.

Keep a Personal Cheat Sheet

The patterns above handle the common cases, but you’ll accumulate your own over time — log formats specific to your stack, identifier schemas from internal systems, date formats your data team insists on using. A short, curated file of tested patterns you can paste from is worth more than memorizing syntax rules. Test them once, annotate them with what they’re for, and reference them rather than rebuilding from scratch each time.

Want To enjoy an ad-free experience? Go Ad-Free Today

Install Our Extensions

Add IO tools to your favorite browser for instant access and faster searching

Add to Chrome Extension Add to Edge Extension Add to Firefox Extension Add to Opera Extension

Scoreboard Has Arrived!

Scoreboard is a fun way to keep track of your games, all data is stored in your browser. More features are coming soon!

ADVERTISEMENT · REMOVE?
ADVERTISEMENT · REMOVE?
ADVERTISEMENT · REMOVE?

News Corner w/ Tech Highlights

Get Involved

Help us continue providing valuable free tools

Buy me a coffee
ADVERTISEMENT · REMOVE?