← Back to Blog

Regex to Match Phone Numbers: US, UK and International (2026)

Phone numbers are notoriously difficult to validate with regex. Unlike email addresses, which follow a consistent global format, phone numbers vary enormously by country - in length, separator style, and whether extensions or country codes are required. This guide gives you practical patterns that work for the most common scenarios.

The Problem With Phone Number Validation

Consider how many ways a US number can be written:

(415) 555-2671
415-555-2671
415.555.2671
4155552671
+1 415 555 2671
+14155552671
1-415-555-2671
415 555 2671 ext. 304

All of these represent the same number. Any validation system that rejects formats users commonly type is going to frustrate real customers. The most common mistake is writing an overly strict regex that rejects legitimate formats while providing false security - a regex that passes 0000000000 (structurally valid, obviously fake).

The practical approach: use regex to enforce minimum structure, then store the raw input and normalize it when you need to use it (e.g., for SMS delivery).

US / North American Phone Number Pattern

North American numbers follow NANP (North American Numbering Plan): optional country code 1, 3-digit area code, 3-digit exchange, 4-digit subscriber number.

^(\+1\s?)?(\(?\d{3}\)?[\s.\-]?)(\d{3}[\s.\-]?\d{4})$

This matches:

(415) 555-2671   ✓
415-555-2671     ✓
415.555.2671     ✓
4155552671       ✓
+1 415 555 2671  ✓
+14155552671     ✓

If you want a simpler pattern that is less strict but still catches obvious garbage:

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

This requires exactly 10 digits (NANP standard) with optional separators. It does not allow the +1 country code prefix - useful when you know your users are US-only.

International E.164 Format

E.164 is the ITU standard for international phone numbers. It defines a globally unambiguous format: + followed by country code followed by subscriber number, no separators, maximum 15 digits total.

^\+[1-9]\d{1,14}$

This is the format to use when storing phone numbers in databases or passing them to telephony APIs (Twilio, Vonage, etc.). It is unambiguous and sortable.

+14155552671    ✓  (US)
+442071234567   ✓  (UK, London)
+33123456789    ✓  (France)
+81312345678    ✓  (Japan, Tokyo)
+6512345678     ✓  (Singapore)
+1              ✗  (too short)
14155552671     ✗  (missing +)
+0123456789     ✗  (country code can't start with 0)

Flexible International Pattern

For forms where users from any country enter their number, you need a pattern that accepts various separator styles while still requiring a minimum structure:

^\+?[1-9]\d{1,3}[\s.\-]?\(?\d{1,4}\)?[\s.\-]?\d{1,4}[\s.\-]?\d{1,9}$

This is deliberately loose. It accepts:

  • Optional leading +
  • Country code 1–4 digits
  • Optional area code in parentheses
  • Digits grouped with spaces, dots, or hyphens
  • Total length 7–15 digits (after stripping separators)

For truly international forms, pair this loose pattern with a digit count check: after stripping all non-digit characters (except the leading +), require 7–15 digits.

Country-Specific Patterns

UK Phone Numbers

// UK numbers: 10-11 digits, starting with 0 or +44
^(\+44\s?|0)(1\d{3}|2\d{3}|3\d{3}|7\d{3}|8\d{3})\s?\d{3}\s?\d{3,4}$

// Simplified UK pattern (covers most cases)
^(\+44|0)7\d{9}$       // UK mobile only (07xxx xxxxxx)
^(\+44|0)[1-9]\d{8,9}$ // UK landline and mobile

German Phone Numbers

^(\+49|0)[1-9]\d{1,14}$
// +49 30 12345678 (Berlin)
// 030 12345678
// +49 151 23456789 (mobile)

Australian Phone Numbers

^(\+61|0)[2-9]\d{8}$
// +61 2 9876 5432 (Sydney landline)
// 02 9876 5432
// +61 4 1234 5678 (mobile)

Test Phone Regex Patterns Live

Paste your pattern and a list of phone numbers. See instantly which ones match. Free, runs in your browser.

Open Regex Tester →

Step-by-Step: Extract and Normalize Phone Numbers

The most useful real-world task is often not validation but extraction and normalization: find phone numbers in a body of text and convert them all to E.164 format. Here is how to do it for US numbers:

// JavaScript: extract US numbers from text and normalize to E.164
function extractAndNormalizeUS(text) {
  const pattern = /(\+?1[-.\s]?)?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})/g;
  const results = [];
  let match;
  while ((match = pattern.exec(text)) !== null) {
    // Rebuild as E.164
    const e164 = `+1${match[2]}${match[3]}${match[4]}`;
    results.push(e164);
  }
  return results;
}

const text = "Call us at (415) 555-2671 or 800.555.0100 for support.";
console.log(extractAndNormalizeUS(text));
// ["+14155552671", "+18005550100"]
# Python: extract and normalize
import re

def extract_us_phones(text):
    pattern = r'(\+?1[-.\s]?)?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})'
    matches = re.findall(pattern, text)
    return [f"+1{''.join(m[1:])}" for m in matches]

text = "Call (415) 555-2671 or 1-800-555-0100"
print(extract_us_phones(text))
# ['+14155552671', '+18005550100']

Normalizing User Input Before Storage

When users submit a phone number in a form, strip all formatting before storing. This makes querying and comparison consistent:

// JavaScript: strip to digits only, then format as E.164 (US)
function normalizeUSPhone(input) {
  // Remove everything except digits and leading +
  const digits = input.replace(/[^\d]/g, '');

  if (digits.length === 10) {
    return `+1${digits}`;          // assume US, add country code
  } else if (digits.length === 11 && digits[0] === '1') {
    return `+${digits}`;           // already has country code 1
  }
  return null;                     // not a valid US number
}

console.log(normalizeUSPhone("(415) 555-2671"));   // +14155552671
console.log(normalizeUSPhone("+1 415 555-2671")); // +14155552671
console.log(normalizeUSPhone("415.555.2671"));    // +14155552671

Handling Extensions

Business phone numbers often include extensions. A common approach is to capture the base number and extension separately:

Pattern: ^(\+?1[-.\s]?)?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})(?:\s*(?:ext|x|ext\.)\s*(\d{1,6}))?$

Input: "(415) 555-2671 ext. 304"
Group 2: "415"
Group 3: "555"
Group 4: "2671"
Group 5: "304"   (extension)

Frequently Asked Questions

Should I validate phone numbers with regex or a library?

For US-only applications, a well-crafted regex is sufficient. For international applications, use Google's libphonenumber library (available for JavaScript as libphonenumber-js, Python as phonenumbers, Java natively). It knows the exact valid number ranges for every country and handles edge cases no regex can - for example, that UK mobile numbers must start with 07, or that certain number ranges are unallocated. Regex can catch obvious formatting errors; libphonenumber can validate that the number could actually exist.

Why does my phone regex reject numbers from certain countries?

Phone number lengths vary by country. Papua New Guinea has 5-digit subscriber numbers. The US has 10. Some satellite phone systems use 15 digits. If you are using a rigid length pattern like \d{10}, it will reject any non-US number. For international acceptance, validate digit count in the range 7–15 (the E.164 maximum is 15 digits including country code).

How do I allow extensions in phone number validation?

Add an optional group at the end that matches common extension notations: (?:\s*(?:ext|x|ext\.?|extension)\s*\d{1,6})?. Make it optional with ? so numbers without extensions still validate. Store the extension separately if you need to dial it programmatically - most telephony APIs have a separate extension or DTMF parameter.

What is the difference between E.164 and local format?

E.164 is the international standard: + plus country code plus subscriber number, no spaces or hyphens, maximum 15 digits total. Local format is country-specific: (415) 555-2671 in the US, 0171 123 4567 in Germany, etc. E.164 is the format to use in databases and APIs because it is globally unambiguous. Local format is what users type and what you display. The workflow is: accept local format from users, normalize to E.164 for storage, display as local format for the user's locale.

Can I use HTML5 input type="tel" instead of regex?

The <input type="tel"> element does not enforce any format - it shows a numeric keyboard on mobile devices but accepts any text. It provides no built-in validation. You still need a regex or library to validate the content. The combination of type="tel" (for better UX on mobile) plus a pattern attribute with your regex is the recommended approach for HTML forms: <input type="tel" pattern="^\(?[0-9]{3}\)?[-. ]?[0-9]{3}[-. ]?[0-9]{4}$">.

The Bottom Line

Phone number validation with regex requires choosing the right level of strictness for your use case. For US-only forms, use a flexible NANP pattern that accepts common separator styles. For international forms, either use a deliberately loose pattern (7–15 digits, optional separators) or invest in libphonenumber. Always store in E.164 format after normalization - it is the only format that is globally unambiguous and safe to pass to telephony APIs.

The cardinal rule: never reject a number based on separator style. Users write (415)-555-2671, 415.555.2671, and 4155552671 all the time. All are equally valid. Strip the formatting, count the digits, and that is your validation.

Use our free tool here → Regex Tester to test phone number patterns against real-world inputs and see which formats your pattern accepts and rejects.

UK
Written by Usman Khan
DevOps Engineer | MSc Cybersecurity | CEH | AWS Solutions Architect

Usman has 10+ years of experience securing enterprise infrastructure, managing high-traffic servers, and building zero-knowledge security tools. Read more about the author.