Cette page est disponible en anglais uniquement. La navigation reste dans votre langue.

Testing & QA · 6 min read

Postal Code Format by Country: 2026 Regex Reference

Postal code formats for 38 countries with working regexes: numeric and alphanumeric systems, no-postal countries, normalization rules, and a test corpus.

By Charlie Simmon ·

On this page
  1. Why postal codes are not a numeric field
  2. Numeric systems and their ranges
  3. Alphanumeric systems and their character rules
  4. Countries with no postal code
  5. Structure checks versus existence checks
  6. Regex details that cause production bugs
  7. Normalize on write, format on display
  8. A test corpus you can copy
  9. Questions

Postal code formats are not interchangeable, and a validator that assumes five digits will reject most of the world. The differences are structural, not cosmetic: some systems are numeric with leading zeros, some mix letters and digits, some place the code before the city, and two countries in this site's fixture set have no postal codes at all.

This reference collects the patterns that matter for a developer building an address form, with regexes you can test directly. It also draws the line the site itself draws: postal validation here is a structure check for every country, plus an existence check for US ZIPs against a 40,979-row dataset. Nothing in this guide implies that a matching code is assigned or deliverable.

Why postal codes are not a numeric field

The United States uses five digits or ZIP+4, which tempts developers to model postal codes as integers. That model breaks immediately in Canada, the United Kingdom, the Netherlands, Ireland, Malta, and Argentina, where letters are part of the code. It also breaks quietly in Germany, France, Spain, Italy, and Poland, where leading zeros are meaningful and an integer column drops them.

A second class of bugs comes from position. Most Western countries put the postal code after the city, but Germany, France, the Netherlands, and Japan place it before the city, and Japan puts the whole code at the very start of the address. If your form renders a fixed template, it will produce addresses that a local reader finds obviously wrong even though every field is populated.

  • Always store postal codes as text, never as integers
  • Keep leading zeros intact through every layer including CSV export
  • Allow letters unless the country is strictly numeric
  • Do not assume the postal code follows the city
  • Treat the separator as presentation, not structure

Numeric systems and their ranges

Most of Europe uses fixed-length numeric codes. Germany, France, Spain, Italy, Greece, Turkey, and Saudi Arabia use five digits; Austria, Belgium, Switzerland, Denmark, Norway, Hungary, and South Africa use four; Poland and Portugal add a hyphen; Sweden uses three digits, a space, and two. Czechia is five digits typically written with a space after the third.

Asia and Latin America are mostly numeric but with different lengths. India, China, Russia, Singapore, and Nigeria use six digits; Japan uses seven with a conventional hyphen after the third; South Korea uses five; Brazil uses eight with a hyphen after the fifth; Chile uses seven; Colombia uses six; Peru and Mexico use five. Length alone is not enough to identify a country, which is why a validator needs the country field before it validates anything.

CountryLengthCanonical formRegex
Germany5 digits10115^\d{5}$
France5 digits75008^\d{5}$
Spain5 digits28013^\d{5}$
Austria4 digits1010^\d{4}$
Poland5 digits with hyphen00-001^\d{2}-\d{3}$
Portugal7 digits with hyphen1250-096^\d{4}-\d{3}$
Sweden5 digits with space114 55^\d{3}\s\d{2}$
Japan7 digits with hyphen100-0001^\d{3}-\d{4}$
Brazil8 digits with hyphen01310-100^\d{5}-\d{3}$
India6 digits110001^\d{6}$
South Korea5 digits04524^\d{5}$
Mexico5 digits06600^\d{5}$

Alphanumeric systems and their character rules

Canada uses the A1A 1A1 pattern, and the letters are restricted. The first character cannot be D, F, I, O, Q, U, W, or Z, and the remaining letters cannot be D, F, I, O, Q, or U. The space between the two triplets is conventional. A validator that allows any letter will accept codes that Canada Post never issues.

The United Kingdom uses an outward code of two to four characters followed by a single space and a three-character inward code, as in SW1A 1AA. The Netherlands is four digits, a space, and two uppercase letters. Ireland uses a seven-character Eircode split as a three-character routing key and a four-character unique identifier. Malta is three letters, a space, and four digits. Argentina uses the eight-character CPA, a letter followed by four digits, three letters, for example C1425ABC.

CountryPatternExampleRegex
CanadaA1A 1A1 with restricted lettersK1A 0B1^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ] ?\d[ABCEGHJKLMNPRSTVWXYZ]\d$
United Kingdom2-4 char outward, 3 char inwardSW1A 1AA^[A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}$
Netherlands4 digits, 2 letters1012 AB^\d{4} ?[A-Z]{2}$
Ireland3 char routing key, 4 char identifierD02 X285^(?:[A-Z]\d{2}|D6W) ?[A-Z0-9]{4}$
Malta3 letters, 4 digitsVLT 1117^[A-Z]{3} ?\d{4}$
ArgentinaLetter, 4 digits, 3 lettersC1425ABC^[A-Z]\d{4}[A-Z]{3}$

Countries with no postal code

Hong Kong and the United Arab Emirates have no postal code system. Both are in this site's 38-country fixture set, and the generator returns an empty postal value for them rather than inventing digits. This is the correct behaviour and it is also a useful test case, because a form that marks postal code as required is broken for both markets.

The UAE convention is a P.O. Box number, which is not a postal code and should not be forced into that field. Hong Kong addresses use the district and street, and mail is delivered without any code. If your data model requires a non-null postal value, use an explicit sentinel such as a country-level flag, not a fake code, because a fake code will pass validation and then fail every downstream check that assumes a real one.

  • Hong Kong: no postal code, district plus street is the address
  • United Arab Emirates: no postal code, P.O. Box is the common convention
  • Make the postal field optional when either country is selected
  • Never substitute 00000 or N/A into a postal column
  • Record the absence explicitly so exports do not look like missing data

Structure checks versus existence checks

A structure check answers whether a string matches the country pattern. An existence check answers whether the code appears in a reference dataset. Only the second can tell you that a code was never assigned. This site performs the structure check for all 38 countries and an existence check for US ZIPs against 40,979 rows, and it labels them differently so nobody confuses one for the other.

Neither check proves deliverability. A five-digit US ZIP can exist while the street address under it does not, and a structurally valid German code can belong to a different city than the one supplied. If you need that level of assurance, you need a postal reference dataset and a street-level database, which is a different product from a format checker.

Check typeCoversProvesDoes not prove
Pattern matchAll 38 countriesWell-formed for that countryThat the code is assigned
US ZIP existence40,979 US ZIP rowsThe code is in the datasetCity or street agreement
Required-field ruleForm levelSubmission can proceedAny real-world validity
Length and charsetField levelStorage will not overflowCountry correctness

Regex details that cause production bugs

Anchor every pattern. An unanchored /\d{5}/ matches the five digits inside a nine-digit string and reports success. Use ^ and $, or the equivalent full-match API. In JavaScript, \d matches only ASCII digits; in Python, \d matches Unicode digits by default, so a pattern can accept Eastern Arabic numerals unless you compile with re.ASCII or write [0-9].

Decide explicitly whether the separator is required. For display, insert the canonical separator yourself. For input, accept zero or one space or hyphen and normalize. Be careful with hyphens inside character classes, where they define ranges unless escaped or placed last. And do not use a case-insensitive flag to paper over a normalization bug: uppercase the value on write and keep the display form canonical.

  • Anchor with ^ and $, or use a full-match function
  • Use [0-9] when you mean ASCII digits
  • Accept optional separators on input, emit canonical separators on display
  • Escape hyphens or place them last inside a character class
  • Uppercase before matching instead of scattering case flags
  • Reject non-breaking spaces and zero-width characters explicitly

Normalize on write, format on display

Store one canonical form and derive the display form. The canonical form is usually uppercase with the standard separator, or digits only when the separator is purely conventional. Keep the raw user input in a separate column if you need an audit trail, because normalization is lossy and a support agent may need to see exactly what was typed.

Country-specific normalization is small but real. Canada wants an uppercase letter-digit-letter space digit-letter-digit. The Netherlands wants uppercase letters after the digits. The UK wants a single space and uppercase. Brazil and Japan use a hyphen that users frequently omit, so normalize to the hyphenated form. Germany wants no separator at all and must keep the leading zero.

CountryRaw inputStored canonicalDisplay
Canadak1a0b1K1A 0B1K1A 0B1
Netherlands1012ab1012 AB1012 AB
United Kingdomsw1a1aaSW1A 1AASW1A 1AA
Brazil0131010001310-10001310-100
Japan1000001100-0001100-0001
Germany101151011510115
Sweden11455114 55114 55

A test corpus you can copy

Every validator needs a corpus with at least one valid and one invalid case per country, plus cases that specifically test normalization and storage. The table below is a starting set. Notice that several invalid cases are invalid for country-specific reasons rather than generic ones, which is where most hand-written tests stop too early.

Add cases for the countries with no postal code, for leading zeros, and for the separator variants users actually type. If the validator is shared between client and server, run the same corpus against both implementations; a divergence between a permissive client and a strict server is the most common source of "the form accepted it but the API rejected it" reports.

CaseValueCountryExpected
Valid ZIP+497205-2515United StatesAccept
Invalid ZIP+497205-251United StatesReject
Valid CanadianK1A 0B1CanadaAccept
Bad Canadian letterD1A 0B1CanadaReject
Valid UKSW1A 1AAUnited KingdomAccept
Missing UK inwardSW1AUnited KingdomReject
German leading zero01067GermanyAccept and preserve
Letters in a numeric system1011AGermanyReject
No codeHong KongAccept as empty
Invented code99999United Arab EmiratesReject the field

Questions

Which countries have no postal codes?+
Hong Kong and the United Arab Emirates have none, and both are in this site's 38-country fixture set. The generator returns an empty postal field for them instead of inventing a value.
Does a valid postal code mean the address is real?+
No. A structural match only means the value is well formed. Only US ZIPs get an existence check here, against 40,979 rows, and no country gets a deliverability claim.
Should postal codes be stored as integers?+
Never. Canada, the UK, the Netherlands, Ireland, Malta, and Argentina use letters, and Germany, France, Spain, Italy, and Poland have meaningful leading zeros.
Why does the Netherlands put letters after the digits?+
The Dutch code is four digits followed by two uppercase letters, for example 1012 AB. The letters are part of the code, not a region suffix, and a digits-only regex rejects valid addresses.
How should I handle the space in a UK or Canadian code?+
Accept input with zero or one space, uppercase it, and store a single canonical separator. Emit the canonical form for display rather than echoing whatever the user typed.

Examples are synthetic. Do not use a generated address for identity checks, account registration, or delivery.

Reference standards

Read next

All guides