Regex Irish PPS number (Personal Public Service)
A PPS number has 7 digits, a check letter (A to W) and optionally a second letter. Per the DG TAXUD specification, the check letter is in [A-W] and the second letter in [A-I] or 'W'. The key is a modulo 23: the 7 digits are weighted 8 down to 2 (the first digit by 8) and the second letter, if present, counts 1 to 9 with weight 9 ('W' or absence counts 0); the remainder gives the letter, 0 being 'W', 1 'A', up to 22 for 'V'. A regex does not compute that modulo: it bounds the shape. The three real attempts I read differ on the second letter: one accepts any word character, another adds historical letters, the third ignores case handling.
/^\d{7}[A-W][A-IW]?$/passes 26/26 cases
Comparison of existing patterns
| Source | pattern | Score on the corpus | ReDoS |
|---|---|---|---|
| validator.js isTaxID (en-IE, drapeau i) — même structure que le motif recommandé mais insensible à la casse : « 1234567tw » passe | ^\d{7}[A-W][A-IW]{0,1}$ | 25 / 26 | safe |
| Relativity aiR (exemple de regex PPS) — « \w{1,2} » : n'importe quel caractère de mot en 8e et 9e position (« 1234567__ », « 12345678 », « 1234567zz » passent), non ancré | \b\d{7}\w{1,2}\b | 20 / 26 | safe |
| piigex (détecteur ie_pps) — seconde lettre [ABHWTX] : accepte les lettres historiques T et X (« 1234567TX », « 1234567TT ») que la spécification DG TAXUD ne liste pas ; lookarounds sans ancres de chaîne (« PPS 1234567T » passe) | (?<![A-Za-z0-9])\d{7}[A-W][ABHWTX]?(?![A-Za-z0-9]) | 24 / 26 | safe |
Implementation
const re = new RegExp("^\\d{7}[A-W][A-IW]?$", "");
re.test(input);Limits
- Valide seulement la FORME : la lettre de contrôle modulo 23 n'est pas vérifiée. « 1234567A » (la bonne lettre est T) passe. Complément : s = Σ chiffre × (8 − i) pour les 7 chiffres + 9 × rang de la seconde lettre (A=1 … I=9, W ou aucune = 0) ; la lettre attendue est « W » si s % 23 = 0, sinon la lettre de rang s % 23.
- La seconde lettre suit la spécification DG TAXUD ([A-I] ou W). Des lettres historiques « T » et « X » (numéros d'avant 2013, d'après python-stdnum) sont donc refusées : « 6433435FT » est rejeté ; remplacez le groupe par [A-IWTX] si vous devez les accepter. La casse est stricte (majuscules).
- Ne dit rien de l'attribution du numéro (un PPS est une donnée personnelle) ; n'utilisez en test que les numéros d'exemple du document officiel ou synthétiques.