Regex patterns by country
| Country | Pattern | Example |
|---|---|---|
| United States | ^\d{5}(?:[-\s]\d{4})?$ | 10001, 10001-2062 |
| United Kingdom | ^[A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}$ | SW1A 1AA |
| Canada | ^[ABCEGHJ-NPRSTVXY]\d[ABCEGHJ-NPRSTV-Z] ?\d[ABCEGHJ-NPRSTV-Z]\d$ | K1A 0B1 |
| Germany | ^\d{5}$ | 10115 |
| France | ^\d{5}$ | 75008 |
| Netherlands | ^\d{4} ?[A-Z]{2}$ | 1012 AB |
| India | ^[1-9]\d{5}$ | 110001 |
| Brazil | ^\d{5}-?\d{3}$ | 01310-100 |
| Japan | ^\d{3}-?\d{4}$ | 100-0001 |
| Australia | ^\d{4}$ | 2000 |
| Spain | ^\d{5}$ | 28013 |
| Italy | ^\d{5}$ | 00184 |
| Poland | ^\d{2}-\d{3}$ | 00-950 |
| Portugal | ^\d{4}-\d{3}$ | 1000-001 |
| Sweden | ^\d{3} ?\d{2}$ | 111 22 |
| Switzerland | ^\d{4}$ | 8001 |
| Austria | ^\d{4}$ | 1010 |
| Ireland (Eircode) | ^(?:[AC-FHKNPRTV-Y]\d{2}|D6W) ?[0-9AC-FHKNPRTV-Y]{4}$ | D02 X285 |
| Mexico | ^\d{5}$ | 06600 |
| South Korea | ^\d{5}$ | 03187 |
Each country page lists the official pattern from Google’s address metadata.
JavaScript
const POSTAL = {
US: /^\d{5}(?:[-\s]\d{4})?$/,
GB: /^[A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}$/i,
CA: /^[ABCEGHJ-NPRSTVXY]\d[ABCEGHJ-NPRSTV-Z] ?\d[ABCEGHJ-NPRSTV-Z]\d$/i,
DE: /^\d{5}$/,
};
function isValidPostalFormat(code, country) {
const re = POSTAL[country];
return re ? re.test(code.trim()) : true; // unknown country: don't block
}
Python
import re
POSTAL = {
"US": re.compile(r"^\d{5}(?:[-\s]\d{4})?$"),
"GB": re.compile(r"^[A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}$", re.I),
"NL": re.compile(r"^\d{4} ?[A-Z]{2}$", re.I),
}
def is_valid_postal_format(code: str, country: str) -> bool:
pattern = POSTAL.get(country)
return bool(pattern.match(code.strip())) if pattern else True
PHP
$postal = [
'US' => '/^\d{5}(?:[-\s]\d{4})?$/',
'CA' => '/^[ABCEGHJ-NPRSTVXY]\d[ABCEGHJ-NPRSTV-Z] ?\d[ABCEGHJ-NPRSTV-Z]\d$/i',
'BR' => '/^\d{5}-?\d{3}$/',
];
function isValidPostalFormat(string $code, string $country, array $postal): bool
{
return isset($postal[$country]) ? (bool) preg_match($postal[$country], trim($code)) : true;
}
When a regex is not enough
99999 matches the US pattern but is not a ZIP code, and SW1A 1ZZ matches the UK pattern but does not exist. To know that a code is real, and to fill in city and state automatically, look it up:
curl "https://api.zipcodestack.com/v1/validate?code=99999&country=us" -H "apikey: YOUR-API-KEY"
# { "result": { "valid": false, "format_valid": true, ... } }
Try it without code in the free postal code validator.