jeudi 21 mai 2026

How to Validate Email, URL & Phone Number with Regex

Form validation is one of those tasks every developer has to implement, usually multiple times across different projects. And every time, the same question comes up: what's the right regex for validating this field?

This guide answers that question for the three most common validation scenarios — email addresses, URLs, and phone numbers — with tested patterns, real code in JavaScript, Python, and PHP, and honest notes on where regex alone isn't enough.

Before we dive in: Regex validates format, not existence. A regex can confirm that user@example.com looks like a valid email — it cannot confirm the mailbox exists. Keep this distinction in mind throughout.

1. Email Address Validation

Email validation is deceptively complex. The full RFC 5322 specification for valid email addresses is extraordinarily permissive — technically, "user name"@[192.168.1.1] is a valid email. In practice, you want a pattern that catches typos without being so strict it rejects real addresses.

The Patterns — From Simple to Strict

Level Pattern Allows Use when
Basic [\w.+-]+@[\w-]+\.[\w.]+ Most emails Quick extraction from text
Standard ✅ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ 99% of real emails Form validation (recommended)
Strict ^(?!.*\.\.)(?!.*\.$)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z]{2,}$ RFC closer When false positives are costly
Recommendation: Use the Standard pattern for almost all form validation. It's strict enough to catch obvious typos, permissive enough not to reject legitimate addresses like user+tag@sub.example.co.uk.

Email Validation in JavaScript

// Standard email validation
function isValidEmail(email) {
  const pattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
  return pattern.test(email.trim());
}

// Test cases
isValidEmail("user@example.com");        // ✅ true
isValidEmail("user+tag@sub.domain.co.uk"); // ✅ true
isValidEmail("user.name@company.io");    // ✅ true
isValidEmail("notanemail");               // ❌ false
isValidEmail("missing@domain");          // ❌ false
isValidEmail("@nodomain.com");           // ❌ false

// For React forms
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
const isValid = emailRegex.test(formData.email);

Email Validation in Python

import re

def is_valid_email(email: str) -> bool:
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    return bool(re.match(pattern, email.strip()))

# Extracting multiple emails from text
def extract_emails(text: str) -> list:
    pattern = r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
    return re.findall(pattern, text)

# Test
is_valid_email("alice@example.com")  # → True
is_valid_email("not-valid")           # → False

Email Validation in PHP

// Method 1: PHP built-in filter (recommended)
function isValidEmail($email): bool {
    return filter_var(trim($email), FILTER_VALIDATE_EMAIL) !== false;
}

// Method 2: Regex (when you need custom rules)
function isValidEmailRegex($email): bool {
    $pattern = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
    return (bool) preg_match($pattern, trim($email));
}

// PHP tip: always use filter_var for email — it handles edge cases better than regex
PHP tip: PHP's built-in filter_var($email, FILTER_VALIDATE_EMAIL) is more accurate than a hand-rolled regex pattern. Use it when PHP is available; use regex in other languages or when you need custom rules.

2. URL Validation

URL validation is where regex quickly becomes unreliable — URLs can be extraordinarily complex, and edge cases multiply fast. The right approach depends on what you actually need to validate.

Choosing Your Approach

Approach When to use Pros Cons
URL constructor (JS) JavaScript validation Most accurate, handles all edge cases JS only
Regex (simple) Basic http/https check Fast, cross-language, customizable Edge cases
filter_var (PHP) PHP URL validation Built-in, reliable PHP only
urllib.parse (Python) Python URL parsing Full URL decomposition Python only

URL Validation in JavaScript — Best Practice

// Method 1: URL constructor (recommended — most accurate)
function isValidUrl(string) {
  try {
    const url = new URL(string);
    return url.protocol === 'http:' || url.protocol === 'https:';
  } catch {
    return false;
  }
}

// Method 2: Regex (when URL constructor isn't available)
function isValidUrlRegex(url) {
  const pattern = /^https?:\/\/(www\.)?[-\w]+\.\w{2,}(\/\S*)?$/i;
  return pattern.test(url);
}

// Test cases
isValidUrl("https://youkip.com");           // ✅
isValidUrl("https://sub.domain.co.uk/path");  // ✅
isValidUrl("http://192.168.1.1:8080");       // ✅
isValidUrl("ftp://example.com");            // ❌ (not http/https)
isValidUrl("not a url");                   // ❌

URL Validation in Python

from urllib.parse import urlparse
import re

def is_valid_url(url: str) -> bool:
    """Validate URL using urlparse (recommended)"""
    try:
        result = urlparse(url)
        return all([result.scheme in ('http', 'https'),
                    result.netloc,
                    '.' in result.netloc])
    except:
        return False

def is_valid_url_regex(url: str) -> bool:
    """Regex-based URL validation"""
    pattern = r'^https?://[\w.-]+\.\w{2,}(/\S*)?$'
    return bool(re.match(pattern, url))

# Extracting URLs from text
def extract_urls(text: str) -> list:
    pattern = r'https?://[\w.-]+\.\w{2,}(?:/\S*)?'
    return re.findall(pattern, text)

URL Validation in PHP

// Method 1: Built-in filter (recommended)
function isValidUrl($url): bool {
    return filter_var($url, FILTER_VALIDATE_URL) !== false;
}

// Method 2: Regex (for http/https only)
function isValidHttpUrl($url): bool {
    if (!filter_var($url, FILTER_VALIDATE_URL)) return false;
    $scheme = parse_url($url, PHP_URL_SCHEME);
    return in_array($scheme, ['http', 'https']);
}

// Specific patterns for URLs in content
$pattern = '/https?:\/\/(www\.)?[-\w]+\.\w{2,}(\/\S*)?/i';
preg_match_all($pattern, $content, $matches);

3. Phone Number Validation

Phone number validation is the hardest of the three. Phone number formats vary wildly between countries, and a "valid" pattern for one country is completely wrong for another. Here's how to handle it properly.

Patterns by Country & Format

Format Pattern Valid examples
International (E.164)^\+[1-9]\d{6,14}$+12125551234, +442071838750
Flexible international^\+?[\d\s\-().]{7,20}$+1 (212) 555-1234
🇲🇦 Morocco^(\+212|00212|0)[5-7]\d{8}$+212612345678, 0612345678
🇺🇸 USA^(\+1)?[\s.-]?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$(212) 555-1234, +12125551234
🇫🇷 France^(\+33|0)[1-9](\s?\d{2}){4}$+33612345678, 06 12 34 56 78
🇬🇧 UK^(\+44|0)\d{10}$+447911123456, 07911 123456
🇩🇪 Germany^(\+49|0)\d{10,11}$+4917612345678
Digits only (any length)^\d{7,15}$Stripped of formatting

Phone Validation in JavaScript — With Auto-Formatting

// Validate international phone (E.164 format)
function isValidPhone(phone) {
  const e164 = /^\+[1-9]\d{6,14}$/;
  return e164.test(phone);
}

// Moroccan phone numbers specifically
function isValidMoroccanPhone(phone) {
  const pattern = /^(\+212|00212|0)[5-7]\d{8}$/;
  return pattern.test(phone.replace(/[\s\-]/g, ''));
}

// Normalize before validating (remove spaces, dashes, parentheses)
function normalizePhone(phone) {
  return phone.replace(/[\s\-().]/g, '');
}

const raw = "+212 06-12-34-56-78";
const normalized = normalizePhone(raw); // → "+212061234568"
isValidMoroccanPhone(normalized);       // → true

Phone Validation in Python

import re

def normalize_phone(phone: str) -> str:
    """Remove spaces, dashes, parentheses"""
    return re.sub(r'[\s\-().]', '', phone)

def is_valid_international(phone: str) -> bool:
    phone = normalize_phone(phone)
    return bool(re.match(r'^\+[1-9]\d{6,14}$', phone))

def is_valid_moroccan(phone: str) -> bool:
    phone = normalize_phone(phone)
    return bool(re.match(r'^(\+212|00212|0)[5-7]\d{8}$', phone))

# Using phonenumbers library (pip install phonenumbers) — most accurate
import phonenumbers
def is_valid_phone_lib(phone: str, country: str = "MA") -> bool:
    try:
        parsed = phonenumbers.parse(phone, country)
        return phonenumbers.is_valid_number(parsed)
    except:
        return False
Pro tip: For serious phone validation (especially multi-country), use Google's libphonenumber. Python: phonenumbers. JavaScript: libphonenumber-js. PHP: giggsey/libphonenumber-for-php. These libraries handle all country formats correctly — no regex required.

4. Combined Form Validation

Real-world example: validating a complete registration form with all three fields in JavaScript.

const validators = {
  email: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
  url:   /^https?:\/\/(www\.)?[-\w]+\.\w{2,}(\/\S*)?$/i,
  phone: /^\+?[\d\s\-().]{7,20}$/,
};

function validateForm(data) {
  const errors = {};

  if (!validators.email.test(data.email?.trim())) {
    errors.email = 'Please enter a valid email address';
  }
  if (data.website && !validators.url.test(data.website?.trim())) {
    errors.website = 'Please enter a valid URL (include http:// or https://)';
  }
  if (data.phone && !validators.phone.test(data.phone?.trim())) {
    errors.phone = 'Please enter a valid phone number';
  }

  return {
    isValid: Object.keys(errors).length === 0,
    errors
  };
}

// Usage
const result = validateForm({
  email: "user@example.com",
  website: "https://youkip.com",
  phone: "+212612345678"
});
console.log(result.isValid); // → true

5. Common Validation Mistakes

❌ Mistake 1: Rejecting valid emails

Patterns that reject user+tag@example.com or name@subdomain.example.co.uk are too strict. Both are perfectly valid.

❌ Mistake 2: Validating phone numbers without normalizing first

"+212 06-12-34-56-78" and "+212061234568" are the same number. Always strip spaces, dashes, and parentheses before running your regex.

❌ Mistake 3: Using regex to validate URLs in PHP when filter_var is available

PHP's built-in FILTER_VALIDATE_URL handles far more edge cases than a hand-written pattern. Use it.

❌ Mistake 4: Forgetting to trim input

A trailing space in "user@example.com " will fail most email patterns. Always .trim() or strip() before validating.

❌ Mistake 5: Assuming format-valid = deliverable

nonexistent@totallyrealcompany.com passes email regex. It doesn't exist. For email marketing or critical communications, add a deliverability check via API.

6. Test Your Patterns Before Deploying

Every pattern in this guide was tested in YouKip Regex Tester Ultra — the free online tool that runs your pattern across 8 languages simultaneously, directly in your browser.

⚡ Test Your Validation Patterns Now

Paste any pattern from this guide. Test it against real input in JavaScript, Python, PHP, and Go simultaneously. 100% free, client-side — nothing sent to any server.

Open Regex Tester → Free
🎁

Get the Complete Regex Cheat Sheet (Free PDF)

50 patterns including email, URL, phone and more — printable PDF, dark mode.

⬇️ Download Free PDF

Last updated: May 2026. All patterns tested across JavaScript, Python, PHP, and Go. Test every pattern against your specific use case before deploying to production — edge cases exist in every regex.