Regex Cheat Sheet: Patterns You Actually Use

Updated 2026-08-31 · 3 min read

Core building blocks

Flags

g find all matches, i ignore case, m make ^ and $ match per line, s let . match newlines, u enable full Unicode. Reusing a g regex across calls carries lastIndex state — a classic source of skipped matches.

Lookahead and lookbehind

(?=…) requires what follows, (?!…) forbids it, and (?<=…) / (?<!…) do the same backwards. Typical use: ^(?=.*\d)(?=.*[a-z]).{8,}$ to assert several conditions on one string without consuming characters.

Patterns worth keeping

Avoid catastrophic backtracking

Nested quantifiers such as (a+)+$ can take exponential time on a crafted input and freeze a server. Prefer specific character classes over .*, and never run a user-supplied pattern on the backend without a timeout.

Greedy, lazy and possessive quantifiers

By default quantifiers are greedy: <.*> against <a>text</a> matches the entire string, because .* takes everything and then backtracks just enough to find a final >. Adding ? makes it lazy — <.*?> matches only <a>.

The better fix is usually neither: use a negated class such as <[^>]*>, which cannot overrun in the first place and runs faster because there is nothing to backtrack. As a rule, prefer "anything except the terminator" over "anything, lazily".

Groups, backreferences and replacement

Capturing groups do double duty: they extract values and they let you refer to what was matched. Inside a pattern, \1 repeats the first group — \b(\w+)\s+\1\b finds accidental doubled words. In a replacement string, $1 or $<name> inserts it.

Named groups make real code readable: (?<year>\d{4})-(?<month>\d{2}) yields match.groups.year instead of a numeric index that shifts every time someone adds a parenthesis. Use non-capturing (?:…) for grouping you do not need to extract.

Unicode-aware matching

\w means [A-Za-z0-9_] and nothing else, so it fails on é, ç, Arabic and Cyrillic. With the u flag you get property escapes: \p{L} for any letter, \p{N} for any number, \p{Script=Arabic} for a specific script.

Emoji and accented characters can also be multiple code points, so . may match half a character. The v flag and the \p{RGI_Emoji} property handle these properly in current engines; for older targets, segment with Intl.Segmenter rather than regex.

Performance and ReDoS in practice

Catastrophic backtracking happens when a pattern can match the same text in exponentially many ways. Nested quantifiers over overlapping sets are the classic trigger, and the failure mode is a request that never returns rather than an error you can see in a log:

When not to use a regex

Regular expressions cannot parse nested structures, which rules out HTML, XML, JSON and source code — the nesting is unbounded and a regex has no memory of depth. Use a real parser; every project that tried the shortcut ended up with a fragile pattern nobody dares to touch.

The same applies to email addresses beyond a loose shape check, to CSV with quoted fields containing commas and newlines, and to natural-language dates. Regex is excellent for tokenising, validating simple shapes, and finding and replacing — not for structure.

Testing patterns before you ship them

Build a small suite of inputs before you write the pattern: three that must match, three that must not, and one deliberately hostile long string. Patterns tuned only against happy-path examples almost always over-match.

Then keep the pattern readable. Multi-line mode with comments, or simply a well-named constant next to a sentence explaining the intent, saves the next reader — usually you in six months — from reverse-engineering it character by character.

Test your pattern live

Build patterns in the Regex Tester with live match highlighting and flag toggles, then paste the working expression into your code.

Try the Regex Tester →Test JavaScript regular expressions live with match highlighting, flag support (g, i, m, s, u) and instant feedback. Free, no signup.

Frequently asked questions

Should I validate email with regex?

Use a loose pattern for shape only and confirm the address with a verification email — the full RFC grammar is impractical.

Does the same regex work in Python and JavaScript?

Mostly, but escapes, named groups and Unicode behaviour differ. Test in the language you ship.

How do I match across multiple lines?

Use the s flag so . matches newlines, and the m flag so ^ and $ anchor to each line instead of the whole string.

Why does my global regex skip matches?

A regex with the g flag stores lastIndex between calls. Create a fresh regex, or reset lastIndex to 0 before reusing it.

Can regex parse HTML?

No. HTML nesting is unbounded and regular expressions cannot track depth. Use a DOM parser.

More guides

How Many Words Is a 5-Minute Speech?A 5-minute speech is roughly 625–750 words at a normal speaking pace. See word counts for 1, 3, 5, 10 and 20-minute talks, plus how to check yours instantly.How to Validate JSON and Fix Common Syntax ErrorsLearn how to validate JSON and fix the most common errors: trailing commas, single quotes, unquoted keys, comments and unescaped characters — with examples.Base64 Is Not Encryption: What It Actually DoesBase64 is reversible encoding, not encryption. Learn what Base64 is for, when to use it, its 33% size cost, and safe alternatives for protecting data.How to Decode a JWT SafelyLearn what is inside a JSON Web Token, how to decode the header and payload, how to read exp and iat claims, and why decoding is not verification.