I keep googling the same regex patterns. Here are the ones I actually need, with explanations, gotchas, and test cases.
Match a valid email (loose, RFC-incompliant but practical)
^[^\s@]+@[^\s@]+\.[^\s@]+$Matches anything that looks like an email without trying to validate RFC 5322 (which is famously impossible with regex alone). For real validation, send a confirmation email.
Slugify a string
[^a-z0-9]+
Replace matches with -, then trim leading/trailing dashes.
"Hello World!".toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '')
// => "hello-world"
Match a UUID v4
^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
The 4 at position 13 is the version marker. The first character of the fourth group must be 8, 9, a, or b (that's the variant).
Strip HTML tags (for preview, NOT for sanitization)
<[^>]+>
Fine for "give me a plain-text preview of this HTML." Absolutely NOT fine for sanitizing user input. Use DOMPurify for that.
Match an ISO date (YYYY-MM-DD)
^\d{4}-\d{2}-\d{2}$
Doesn't check that the date is valid (matches 2024-13-99) but catches malformed input.
Capture markdown links
\[([^\]]+)\]\(([^)]+)\)
Group 1 is the link text, group 2 is the URL.
Match a US phone number (lenient)
^\+?1?[-.\s]?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$
Matches 555-555-5555, (555) 555-5555, +1 555.555.5555, 5555555555.
Common gotchas I always forget
Greedy vs lazy
.* matches as much as possible. .*? matches as little as possible. If you're capturing inside quotes, you want lazy: "(.*?)". Greedy "(.*)" will match across multiple strings on the same line.
Anchors and multiline mode
^ and $ match the start and end of the string by default, not the start and end of each line. Add the m flag to make them match line boundaries.
Escaping inside character classes
Inside [ ], most special characters don't need escaping. The ones that do: ], \, ^ (only if first), - (only if between two characters). So [.+*?] matches a literal dot, plus, asterisk, or question mark. No backslashes needed.
Capturing vs non-capturing
(foo) captures. (?:foo) matches but doesn't capture. Use non-capturing when you only need the grouping for repetition or alternation: (?:https?|ftp)://.
A small free tool
If you don't want to memorize any of this, I built a regex generator that takes plain English ("match a URL with optional protocol") and gives back the regex with test cases: tinkrtool.com/regex. Free, no signup. But the patterns above cover 80% of what I actually need.
What patterns do you actually use?
Drop your daily-driver regexes in the comments. Bonus points if yours has a gotcha you only learned about in production.
Top comments (0)