Β· By DevToolHub Team

Regular Expressions Cheat Sheet with Examples

Regular expressions (regex) are a powerful text-matching tool built into virtually every programming language. They can validate input, extract data, and transform text β€” but their compact syntax can be intimidating. This guide is a practical regex cheat sheet with annotated examples β€” character classes, quantifiers, groups, lookaround, and real-world patterns for email, URL, IP, date, and HTML matching. To experiment with patterns interactively, open our free Regex Tester in another tab. For a compact syntax-only reference, see the Regex Cheat Sheet.

The Building Blocks

Literal Characters

Most characters match themselves. The regex cat matches the exact string β€œcat” inside any text. This is the simplest form of regex β€” a literal search.

Character Classes: Matching Types of Characters

Character classes match one character from a defined set:

\d    β†’ any digit (0-9)
\w    β†’ any word character (letters, digits, underscore)
\s    β†’ any whitespace (space, tab, newline)
.     β†’ any character except newline

Uppercase versions are negations: \D = non-digit, \W = non-word, \S = non-whitespace.

Custom sets use square brackets:

[aeiou]     β†’ any vowel
[0-9a-f]    β†’ any hex digit
[^0-9]      β†’ anything that is NOT a digit

Example β€” match a hex color code:

#[0-9a-fA-F]{6}\b

This matches #1a2b3c or #FF9900 but not #xyz or #12 (too short).

Quantifiers: How Many Times

Quantifiers control repetition:

*       β†’ 0 or more
+       β†’ 1 or more
?       β†’ 0 or 1 (optional)
{3}     β†’ exactly 3
{2,5}   β†’ between 2 and 5
{3,}    β†’ 3 or more

Example β€” match a US phone number:

\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}

Breaking it down:

  • \(? β€” optional opening parenthesis
  • \d{3} β€” three digits (area code)
  • \)? β€” optional closing parenthesis
  • [-.\s]? β€” optional separator (dash, dot, or space)
  • \d{3} β€” three digits
  • [-.\s]? β€” optional separator
  • \d{4} β€” four digits

Matches: (555) 123-4567, 555.123.4567, 5551234567

Greedy vs Lazy Matching

By default, quantifiers are greedy β€” they match as much as possible. Adding ? makes them lazy β€” matching as little as possible.

Given the string <b>bold</b> and <b>more</b>:

<b>.*</b>      β†’ matches "<b>bold</b> and <b>more</b>" (greedy β€” one big match)
<b>.*?</b>     β†’ matches "<b>bold</b>" then "<b>more</b>" (lazy β€” two small matches)

When matching content between delimiters, lazy quantifiers or negated character classes ([^<]* instead of .*?) are almost always what you want.

Anchors: Position Matters

Anchors don’t match characters β€” they match positions:

^       β†’ start of string (or line, with m flag)
$       β†’ end of string (or line, with m flag)
\b      β†’ word boundary (between \w and \W)

Example β€” validate that a string is a valid integer (nothing else):

^-?\d+$

Without ^ and $, the regex would match the β€œ42” inside β€œabc42xyz”. The anchors ensure the entire string must be a number.

Example β€” match whole words only:

\bfunction\b

Matches β€œfunction” in function foo() but not β€œdysfunction” or β€œfunctionality”.

Groups and Capturing

Parentheses create groups that serve two purposes: grouping for quantifiers and capturing matched text.

(ha)+         β†’ matches "ha", "haha", "hahaha" (group + quantifier)
(\d{4})-(\d{2})-(\d{2})   β†’ captures year, month, day separately

Named Groups

Named groups make captures self-documenting:

const dateRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2026-04-10'.match(dateRegex);
console.log(match.groups.year);   // "2026"
console.log(match.groups.month);  // "04"

Non-Capturing Groups

Use (?:...) when you need grouping without capturing (slightly more efficient):

(?:https?|ftp)://\S+

Groups https? and ftp as alternatives without creating a capture group.

Back-References

\1, \2, etc. refer back to previously captured groups:

<(\w+)>.*?</\1>

Matches an HTML tag and its closing tag: <div>content</div>. The \1 ensures the closing tag matches the opening tag name.

Lookaround: Assert Without Consuming

Lookaround checks what’s before or after the current position without including it in the match:

(?=...)     β†’ lookahead: what follows
(?!...)     β†’ negative lookahead: what must NOT follow
(?<=...)    β†’ lookbehind: what precedes
(?<!...)    β†’ negative lookbehind: what must NOT precede

Example β€” match a number only if followed by β€œpx”:

\d+(?=px)

In font-size: 16px; margin: 2em, matches 16 but not 2.

Example β€” password validation (must contain at least one digit, one lowercase, one uppercase, minimum 8 characters):

^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$

Each (?=...) is a lookahead that scans the entire string for a required character type without consuming any characters, so all three checks run from the same starting position.

Flags

Flags modify how the regex engine behaves:

FlagNameEffect
gGlobalFind all matches, not just the first
iCase-insensitiveA matches a
mMultiline^/$ match line starts/ends
sDotAll. matches newlines too
'Hello World'.match(/hello/i);     // ["Hello"] β€” case insensitive
'line1\nline2'.match(/^\w+/gm);    // ["line1", "line2"] β€” multiline

Real-World Patterns

Email Validation (Simple)

^[\w.+-]+@[\w-]+\.[\w.]+$

Good enough for most forms. For strict RFC 5322 compliance, the regex would be absurdly long β€” use a library or just send a confirmation email.

URL Extraction

https?://[^\s<>"']+

Matches HTTP(S) URLs by starting with the protocol and consuming everything that isn’t whitespace or common delimiters.

IPv4 Address

\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b

Unlike the simpler \d{1,3}(\.\d{1,3}){3}, this validates that each octet is 0–255.

\[([^\]]+)\]\(([^)]+)\)

Captures the text in group 1 and the URL in group 2. For [Google](https://google.com), group 1 = β€œGoogle”, group 2 = β€œhttps://google.com”.

Find Duplicate Words

\b(\w+)\s+\1\b

Matches β€œthe the”, β€œis is”, etc. The \1 back-reference matches exactly what group 1 captured.

Remove HTML Tags

<[^>]+>

Matches any HTML tag for stripping. Note: this is fine for simple cleanup but not for security-sensitive HTML sanitization β€” use a proper HTML parser for that.

Common Pitfalls

Catastrophic backtracking. Nested quantifiers like (a+)+ can cause the regex engine to try exponentially many paths on non-matching input. Avoid nesting quantifiers where possible, or use atomic groups / possessive quantifiers if your engine supports them.

Forgetting to escape special characters. To match a literal ., *, +, ?, (, ), [, ], {, }, |, ^, $, or \, you must escape it with \.

Multiline confusion. By default, ^ and $ match the start/end of the entire string. To match line boundaries, add the m (multiline) flag. And . doesn’t match newlines unless you add the s (dotAll) flag.

Over-engineering validation. A regex that validates every edge case of an email address is hundreds of characters long. For most validation tasks, a simple regex plus server-side verification is more maintainable than a β€œperfect” regex.

Try It Yourself

Use our Regex Tester to test patterns in real time with match highlighting, capture group extraction, and flag toggles β€” all in your browser.

For a compact quick-reference table, see our Regex Cheat Sheet. If you’re building SEO-friendly URL slugs, regex is often part of the transliteration pipeline. And if you work with encoded strings, the URL encoding guide covers percent-encoding of special characters that sometimes interact with regex patterns.

Further Reading

FAQ

What is the difference between .* and .*? in regex?
.* is greedy β€” it matches as many characters as possible. .*? is lazy (non-greedy) β€” it matches as few characters as possible. For example, given the string "<b>one</b> <b>two</b>", the pattern <b>.*</b> matches the entire string (greedy), while <b>.*?</b> matches only "<b>one</b>" (lazy). Use lazy quantifiers when you want the shortest possible match.
Why does my regex match more than I expected?
Most likely you're using greedy quantifiers (.*, .+) that consume as much text as possible. Try switching to lazy versions (.*?, .+?) or use negated character classes like [^<]+ instead of .+ when matching up to a specific delimiter. Also check if you're missing anchors (^ and $) β€” without them, the regex can match anywhere in the string.
How do I match a literal special character like . or * in regex?
Escape it with a backslash: \. matches a literal dot, \* matches a literal asterisk. The special characters that need escaping are: . * + ? ^ $ | \ ( ) [ ] { }. Inside a character class [ ], most special characters lose their meaning except ], \, ^, and -.
What is a lookahead and when should I use it?
A lookahead (?=...) checks that a pattern follows the current position without consuming characters. Use it when you need to assert that something comes next without including it in the match. Common uses: password validation (must contain a digit: (?=.*\d)), matching a word only if followed by specific punctuation, or splitting on a pattern without removing the delimiter.
Are regular expressions the same across all programming languages?
The core syntax (character classes, quantifiers, basic groups) is nearly identical everywhere. However, advanced features differ: JavaScript lacks possessive quantifiers and conditionals. Python uses (?P<name>) for named groups while JavaScript uses (?<name>). .NET and Java support more features than JavaScript. POSIX regex (grep, sed) uses different syntax for groups and quantifiers. Always check your language's regex documentation.
How do I test a regex without running my full code?
Use a regex tester β€” an online tool where you enter a pattern, paste sample text, and immediately see matches highlighted with capture groups extracted. Our [Regex Tester](/tools/regex-tester/) runs in your browser and supports all standard flags. Other popular options include regex101.com and regexr.com.
What is the most common regex mistake?
Forgetting that the dot (.) does not match newlines by default. If your pattern uses .* to match content across multiple lines, you need the dotAll flag (s) β€” otherwise the regex stops at the first newline. The second most common mistake is using greedy quantifiers when lazy ones are needed: <b>.*</b> matches everything between the first <b> and the last </b>, while <b>.*?</b> matches each pair separately.
regex programming reference text productivity

Related Tools

Related Articles