Course:Internet & Tools/
Lesson

Now that you know the building blocks, it is time to apply them to the patterns you will encounter constantly in real projects. This lesson walks through the most common validation use cases, explains the reasoning behind each pattern, and gives you honest guidance on when to keep things simple versus when to reach for a library.

Email validation

Simple approach

The technically correct regexWhat is regex?A compact pattern language for matching, searching, and replacing text, built into nearly every programming language and code editor. for email addresses according to RFC 5321 is over a thousand characters long and still does not cover every edge case. For client-side validation, this simple pattern covers the overwhelming majority of real-world email addresses.

const simpleEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

simpleEmail.test('user@example.com');    // true
simpleEmail.test('name+tag@domain.co.uk'); // true
simpleEmail.test('@example.com');        // false - nothing before @
simpleEmail.test('user@');               // false - nothing after @

Breaking it down: [^\s@]+ means "one or more characters that are not whitespace or @." That covers the local part, the domain, and the TLDWhat is tld?Top-Level Domain - the last segment of a domain name (.com, .org, .fr), indicating the domain's type or country. without being so strict that you accidentally reject valid addresses.

Stricter version

If you need to be more explicit about which characters are allowed:

const strictEmail = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
The only reliable way to validate an email address is to send a message to it and see if the user can click the link. Regex can check format, but it cannot check whether the address actually exists or belongs to the person who entered it.
02

URL validation

Basic URL check

// Requires http:// or https://
const basicUrl = /^https?:\/\/[^\s/$.?#].[^\s]*$/i;

basicUrl.test('https://example.com');       // true
basicUrl.test('http://site.org/path?q=1');  // true
basicUrl.test('ftp://files.example.com');   // false - not http/https

Domain only (no protocolWhat is protocol?An agreed-upon set of rules for how two systems communicate, defining the format of messages and the expected sequence of exchanges.)

const domainOnly = /^(?:[\w-]+\.)+[\w-]{2,}$/;

domainOnly.test('example.com');        // true
domainOnly.test('sub.domain.co.uk');   // true
domainOnly.test('localhost');          // false - no dot
For production URL validation, consider using the built-in URL constructor instead of regex. new URL(input) throws if the URL is malformed, wrap it in a try/catch and you have a reliable validator with zero regex complexity.
03

Phone numbers

Phone numbers are notoriously inconsistent. Users enter them with dashes, dots, spaces, parentheses, country codes, and no separators at all. The practical approach is to accept the formats common in your user base and normalise them server-side.

// US phone - accepts common formats
const usPhone = /^(\+?1[-.\s]?)?\(?([0-9]{3})\)?[-.\s]?([0-9]{3})[-.\s]?([0-9]{4})$/;

// All of these match:
usPhone.test('555-123-4567');    // true
usPhone.test('(555) 123-4567'); // true
usPhone.test('555.123.4567');   // true
usPhone.test('5551234567');     // true
usPhone.test('+1 555-123-4567'); // true

// International format (E.164)
const intlPhone = /^\+[1-9]\d{1,14}$/;
intlPhone.test('+14155552671');  // true
intlPhone.test('+33123456789'); // true
04

Password validation

Using lookaheads

A lookahead ((?=...)) checks that a condition is satisfied at the current position without actually consuming any characters. This lets you write multiple independent rules into a single pattern.

// Requires: 8+ characters, one lowercase, one uppercase, one digit
const basicPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/;

basicPassword.test('Hello123');    // true
basicPassword.test('hello123');    // false - no uppercase
basicPassword.test('HELLO123');    // false - no lowercase
basicPassword.test('Hello12');     // false - only 7 characters

// Stronger: also requires a special character and 12+ characters
const strongPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&]).{12,}$/;

Each (?=.*[x]) says: "somewhere ahead in this string, there must be a character matching [x]." The .* before it means "at any position." The final .{8,} is what actually matches and consumes the full string.

05

Date and time patterns

FormatPatternExample match
ISO 8601 (YYYY-MM-DD)/^\d{4}-(0[1-9]\|1[0-2])-(0[1-9]\|[12]\d\|3[01])$/2024-03-15
US date (MM/DD/YYYY)/^(0[1-9]\|1[0-2])\/(0[1-9]\|[12]\d\|3[01])\/\d{4}$/03/15/2024
24-hour time (HH:MM)/^([01]\d\|2[0-3]):([0-5]\d)$/23:59
12-hour time with AM/PM/^(0?[1-9]\|1[0-2]):([0-5]\d)\s?(AM\|PM)$/i11:30 PM

ISO 8601What is iso 8601?An international date and time format standard (e.g., 2024-03-15T10:30:00Z) used in APIs for unambiguous timestamps. date (YYYY-MM-DD)

const isoDate = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;

isoDate.test('2024-03-15');  // true
isoDate.test('2024-13-15'); // false - month 13 does not exist
isoDate.test('2024-02-30'); // false - no 30th of February

Time formats

// 24-hour: HH:MM
const time24 = /^([01]\d|2[0-3]):([0-5]\d)$/;
time24.test('23:59');  // true
time24.test('24:00');  // false

// 12-hour with AM/PM
const time12 = /^(0?[1-9]|1[0-2]):([0-5]\d)\s?(AM|PM)$/i;
time12.test('11:30 PM'); // true
time12.test('13:00 AM'); // false
06

IP addressWhat is ip address?A numerical label (e.g., 172.217.14.206) that identifies a device on a network - DNS translates domain names into IP addresses. validation

// IPv4 - validates each octet is 0–255
const ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;

ipv4.test('192.168.1.1');  // true
ipv4.test('255.255.255.0'); // true
ipv4.test('256.1.1.1');    // false - 256 is out of range

The alternation inside the group, 25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?, handles three ranges: 250–255, 200–249, and 0–199.

07

Quick reference

Use casePatternNotes
Simple email/^[^\s@]+@[^\s@]+\.[^\s@]+$/Good enough for client-side
US phone/^\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$/Flexible format
ISO date/^\d{4}-(0[1-9]\|1[0-2])-(0[1-9]\|[12]\d\|3[01])$/Month/day bounds
Hex color/^#[a-fA-F0-9]{6}$/Standard 6-digit hex
URL slug/^[a-z0-9]+(?:-[a-z0-9]+)*$/Lowercase, hyphen-separated
Password (basic)/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/Lookaheads for rules
IPv4 addresssee aboveValidates octet range
javascript
// Comprehensive validation library
const validators = {
  // Emails
  email: (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email),
  emailStrict: (email) => /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email),

  // URLs
  url: (url) => /^https?:\/\/[^\s/$.?#].[^\s]*$/i.test(url),
  domain: (domain) => /^(?:[\w-]+\.)+[\w-]{2,}$/.test(domain),

  // Phone (US and International)
  phoneUS: (phone) => /^\d{3}[-.]?\d{3}[-.]?\d{4}$/.test(phone.replace(/\D/g, '').replace(/^1/, '')),
  phoneIntl: (phone) => /^\+[1-9]\d{1,14}$/.test(phone.replace(/\s+/g, '')),

  // Passwords
  passwordBasic: (pass) => /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/.test(pass),
  passwordStrong: (pass) => /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&]).{12,}$/.test(pass),

  // Credit Card (format only)
  creditCardFormat: (card) => /^\d{13,19}$/.test(card.replace(/\D/g, '')),

  // Dates
  dateISO: (date) => /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/.test(date),
  dateUS: (date) => /^(0[1-9]|1[0-2])\/(0[1-9]|[12]\d|3[01])\/\d{4}$/.test(date),

  // Network
  ipv4: (ip) => /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ip),

  // User input
  username: (username) => /^[a-zA-Z0-9][a-zA-Z0-9_-]{1,18}[a-zA-Z0-9]$/.test(username),
  slug: (slug) => /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug),

  // Colors
  hexColor: (color) => /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/.test(color),

  // Postal codes
  zipUS: (zip) => /^\d{5}(-\d{4})?$/.test(zip)
};

// Test all validators
const testCases = {
  email: ['test@example.com', 'invalid-email', '@example.com'],
  url: ['https://google.com', 'http://test.org/path', 'not-a-url'],
  phoneUS: ['555-123-4567', '5551234567', '123-45-6789'],
  passwordBasic: ['Hello123', 'hello123', 'HELLO123'],
  dateISO: ['2024-03-15', '2024-13-15', '2024-03-32'],
  ipv4: ['192.168.1.1', '10.0.0.1', '256.1.1.1']
};

Object.entries(testCases).forEach(([validator, inputs]) => {
  console.log(`\n${validator}:`);
  inputs.forEach(input => {
    const result = validators[validator](input);
    console.log(`  ${result ? '✅' : '❌'} ${input}`);
  });
});