Regex Portuguese postal code
A Portuguese postal code is written '1000-205': 4 digits, a hyphen, 3 digits, and the first digit is always 1 to 9, because 0 does not exist. Three real attempts, each wrong in its own way: validator.js writes '\d{3}?' and suggests an optional last digit, but that lazy quantifier changes nothing ('1000-20' fails); a TypeScript library accepts a bare '1000', the legacy 4-digit format from 1976; the GeoNames file accepts a locality name after the code, but not '9500-101 Ponta Delgada', because only a single space is allowed. Here's a strict pattern, compared against those three attempts.
/^[1-9][0-9]{3}-[0-9]{3}$/passes 23/23 cases
Comparison of existing patterns
| Source | pattern | Score on the corpus | ReDoS |
|---|---|---|---|
| GeoNames (countryInfo.txt) — accepte un nom de localité après le code, mais une seule espace et des lettres ASCII : « 9500-101 Ponta Delgada » et « 4700-001 Évora » échouent ; accepte aussi « 0000-000 » | ^\d{4}-\d{3}\s?[a-zA-Z]{0,25}$ | 20 / 23 | safe |
| validator.js — « \d{3}? » n'est pas un dernier chiffre optionnel (quantificateur paresseux sans effet) ; accepte aussi « 0000-000 » (premier chiffre 0 inexistant) | ^\d{4}\-\d{3}?$ | 21 / 23 | safe |
| ts-postcode-validator — groupe « -000 » facultatif : accepte « 1000 » ou « 0000 » seuls, l'ancien format à 4 chiffres, et n'impose pas le premier chiffre 1-9 | ^\d{4}([\-]\d{3})?$ | 20 / 23 | safe |
Implementation
const re = new RegExp("^[1-9][0-9]{3}-[0-9]{3}$", "");
re.test(input);Limits
- Valide seulement la FORME (4 chiffres, tiret, 3 chiffres, premier chiffre 1 à 9) : ne vérifie pas qu'un code est réellement attribué par les CTT. Les 3 derniers chiffres désignent un îlot d'immeubles ou une adresse précise, aucune regex ne peut savoir lesquels existent.
- Rejette le code suivi de la localité (« 1000-205 Lisboa »), qui s'écrit pourtant couramment sur une adresse : séparez le code du nom de localité avant de valider. Rejette aussi le code à 4 chiffres seuls, l'ancien format de 1976, encore vu sur de vieux courriers.
- Le tiret fait partie du format : aucune source consultée ne le déclare facultatif. « 1000205 » est donc rejeté ; si votre saisie l'autorise, normalisez-la avant validation.
- La règle « premier chiffre de 1 à 9 » vient de la page Wikipédia sur les codes postaux portugais (la page des CTT n'a pas pu être consultée) et d'une bibliothèque Django, pas d'une page officielle citée ici : à vérifier si votre cas est sensible.
Postal codes for other countries
- Argentine postal code (CPA)
- Australian postcode
- Brazilian postal code (CEP)
- Canadian postal code
- Czech postal code (PSČ)
- Dutch postal code
- French postal code
- German postal code (PLZ)
- Indian PIN code
- Irish Eircode
- Japanese postal code
- Polish postal code
- Spanish postal code
- Swedish postal code
- Swiss postal code (PLZ/NPA)
- UK postcode
- US ZIP code (ZIP and ZIP+4)
- All postal codes by country