Regular Expressions Cheat Sheet: Email, URL, and Date Patterns Every Developer Reaches For
Three production-ready regex patterns — email, URL, and ISO date — with exact JavaScript examples, edge-case tables, and performance notes.
Regular Expressions Cheat Sheet: Email, URL, and Date Patterns Every Developer Reaches For
Ask any developer which regex patterns they rewrite most often, and the answer is nearly always the same three: email, URL, and date. These come up in every sign-up form, every CSV import pipeline, and every data-cleaning script. The problem is that each one has edge cases that produce bugs in production — the email address containing a + alias, the URL pointing to localhost, the date string that claims February 31 is valid. This article breaks down one working pattern for each, with real JavaScript tests you can copy immediately.
Why These Three Patterns Cover Most Validation Work
In practice, the majority of client-side form validation falls into one of these three categories. According to the OWASP Testing Guide, improper input validation ranks among the most common sources of exploitable web application flaws — and regex is the standard first-line check. Getting email, URL, and date right means you can handle sign-up forms, file import checks, and REST API input guards with a small set of well-understood tools.
That said, a regex is not a full validator. It checks shape, not meaning. A date regex can reject 2026-02-31 if you add conditional month groups, but it will never confirm whether a domain resolves in DNS. Use regex as the fast pre-filter, then pair it with server-side validation for anything that matters.
If you want a complete reference while writing your own patterns, Toolora's Regex Cheatsheet covers every token, quantifier, anchor, and flag across JavaScript, Python, and PCRE — with interactive examples you can try directly on the page.
Email Validation: The Pattern That Actually Works
Most tutorials teach a version that breaks on valid addresses. Here is the pattern I use in JavaScript — it handles + aliases, subdomain addresses, and country-code TLDs while rejecting double-at signs and missing dots:
const emailRe = /^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$/;
Real match table:
| Input | Match? | |---|---| | alice@example.com | ✓ | | bob+filter@mail.example.co.uk | ✓ | | carol@@example.com | ✗ | | dave@.com | ✗ | | eve@example | ✗ — no TLD dot | | frank@example.c | ✗ — TLD shorter than 2 chars |
The {2,} at the end is the detail most short patterns miss. A single-character TLD does not exist in public DNS, and allowing it accepts typos like @example.c silently.
One important limitation: this pattern accepts user@example.com. (trailing dot) because . appears inside the domain character class. If you also run server-side validation, that edge case is caught during DNS resolution. For pure client-side use, change the domain segment to [a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)* to exclude trailing dots explicitly.
I once spent two hours debugging a sign-up form that accepted user@@example.com as valid because the original regex used .* in the local part instead of a proper character class. Replacing .* with [a-zA-Z0-9._%+\-]+ fixed it in one line and caught four more test cases that had been slipping through since launch.
URL Matching: Broad vs Strict Tradeoffs
URL patterns range from "anything that starts with http" to a 3,000-character behemoth that matches every RFC 3986 component. For the vast majority of use cases, this balanced pattern works:
const urlRe = /^https?:\/\/[a-zA-Z0-9\-._~:/?#\[\]@!$&'()*+,;=%]+$/;
Real match table:
| Input | Match? | |---|---| | https://example.com | ✓ | | http://localhost:3000/api?q=test | ✓ | | https://sub.domain.co.uk/path#anchor | ✓ | | ftp://example.com | ✗ — not http/https | | example.com | ✗ — no scheme | | https:// | ✗ — no host after scheme |
The character class covers the full set of unreserved, reserved, and percent-encoded characters from RFC 3986 Section 2. It intentionally excludes bare-domain forms like example.com — if you need those, use a separate pattern and combine the results rather than making one pattern more permissive. A combined "http:// or bare domain" pattern often ends up accepting javascript:void(0) when applied naively.
ISO Date Validation: Avoiding the February-31 Problem
\d{4}-\d{2}-\d{2} matches 2026-02-31, which is not a real date. For a pattern that correctly bounds day ranges per month, you need three branches:
const isoDateRe =
/^\d{4}-(0[13578]|1[02])-(0[1-9]|[12]\d|3[01])$|^\d{4}-(0[469]|11)-(0[1-9]|[12]\d|30)$|^\d{4}-02-(0[1-9]|1\d|2[0-9])$/;
Real match table:
| Input | Match? | |---|---| | 2026-01-15 | ✓ | | 2026-06-30 | ✓ — June has 30 days | | 2026-02-28 | ✓ | | 2026-02-31 | ✗ — February never has 31 days | | 2026-04-31 | ✗ — April has 30 days | | 2026-13-01 | ✗ — no month 13 |
The three branches handle: months with 31 days, months with 30 days, and February (up to day 29 to allow leap years). The pattern does not determine whether a specific year is a leap year — 2026-02-29 passes. If leap-year precision is required, add a Date constructor check after the regex:
function isValidISODate(input) {
if (!isoDateRe.test(input)) return false;
const d = new Date(input);
return !isNaN(d.getTime());
}
new Date("2026-02-29") returns Invalid Date in every modern JavaScript engine, so the combination of regex shape-check plus Date construction gives you both format correctness and calendar correctness.
Testing Patterns Before They Touch Production
Writing the regex is only half the work. Every pattern in this article should be tested against at least five valid inputs and five edge-case invalids before it goes into a codebase. Cloudflare's July 2019 global outage — which took down millions of sites for 27 minutes — was traced directly to a single untested WAF regex rule that triggered catastrophic backtracking on certain HTTP request bodies. The regex fix took one minute to write. Restoring full service took 27 minutes. The lesson: test your patterns with inputs that probe the boundaries, not just the happy path.
To run live matches without leaving the browser, Toolora's Regex Tester lets you paste a pattern, set flags, and see match highlighting across a block of test strings in real time. The capture group panel is particularly useful when you add named groups to extract specific parts of an email domain or URL path — you can confirm that (?<domain>[a-zA-Z0-9.\-]+) captures exactly what you expect before the code ships.
When a pattern needs to handle a new edge case and you want to understand whether to extend the character class or add a new alternation branch, test the modified version against all your existing valid and invalid inputs at once. A quick paste into a live tester catches regressions in under a minute.
Patterns Are the Start, Not the End
The three patterns above are stable enough to use as a starting point in production, with the caveats noted — especially the leap-year check for dates and the DNS lookup for emails that must actually receive messages. A simpler, well-tested pattern that handles 99% of real-world input is almost always better than an exhaustive one that introduces backtracking risk.
The next time you reach for a regex, start with the smallest pattern that describes what you accept, test it against the edges, then expand only when a real failing case demands it. The cheat sheets and testers are there to make each of those steps take seconds rather than minutes.
Made by Toolora · Updated 2026-06-28