Lettre du DNI et du NIE espagnols : algorithme et code
Calcul de la lettre de contrôle du DNI et du NIE espagnols (modulo 23) : code JavaScript, PHP et Python, cas limites et pourquoi elle ne prouve rien.
Par L'équipe Constaia6 min de lecture
En Espagne, les citoyens possèdent un DNI (Documento Nacional de Identidad) : huit chiffres suivis d'une lettre de contrôle, par exemple 12345678Z. Les résidents étrangers ont un NIE (Número de Identidad de Extranjero) : une lettre initiale X, Y ou Z, sept chiffres et une lettre de contrôle. Les deux servent de numéro d'identification fiscale espagnol (NIF) ; on les retrouve donc dans presque tous les formulaires : inscriptions, factures, licences sportives. Si votre plateforme accueille des participants ou des clients espagnols, vous les croiserez.
La lettre de contrôle est la validation la moins coûteuse qui soit : une division et une table de 23 lettres. Pourtant, dans les vrais formulaires, elle échoue plus souvent qu'on ne le croit, à cause des espaces, des tirets, des minuscules, des zéros en tête et des NIE qui commencent par une lettre.
Voici l'algorithme officiel, du code prêt à copier dans trois langages et les cas limites à couvrir. Et pour finir, un avertissement important : une lettre correcte ne prouve pas que le document existe.
L'algorithme officiel
Le ministère espagnol de l'Intérieur le décrit ainsi : on divise le numéro par 23 et on remplace le reste par une lettre selon cette table.
| Reste | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Lettre | T | R | W | A | G | M | Y | F | P | D | X | B |
| Reste | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Lettre | N | J | Z | S | Q | V | H | L | C | K | E |
Écrite d'un seul tenant, la table est la chaîne TRWAGMYFPDXBNJZSQVHLCKE : la lettre est le caractère à la position numéro % 23.
L'exemple officiel : 12345678 divisé par 23 donne un reste de 14, donc la lettre est Z → 12345678Z.
Le NIE
Pour calculer la lettre du NIE, on remplace la lettre initiale par un chiffre, puis on applique le même algorithme (source) :
| Lettre initiale | Remplacée par |
|---|---|
| X | 0 |
| Y | 1 |
| Z | 2 |
Exemples :
X1234567→01234567→ reste 19 → L →X1234567LY1234567→11234567→ reste 10 → X →Y1234567XZ1234567→21234567→ reste 1 → R →Z1234567R
Faites toujours le calcul sur le numéro complet de 8 chiffres après substitution. Si vous ne divisez que les 7 chiffres du NIE, X tombe juste par hasard (un 0 en tête ne change rien), mais Y et Z donnent des lettres fausses.
Le code
Les trois versions font la même chose : normaliser l'entrée, vérifier le format (8 chiffres + lettre, ou X/Y/Z + 7 chiffres + lettre) et comparer la lettre.
const LETTERS = "TRWAGMYFPDXBNJZSQVHLCKE";
export function validateNifNie(input) {
const value = String(input).toUpperCase().replace(/[\s.\-]/g, "");
const match = /^([XYZ]\d{7}|\d{8})([A-Z])$/.exec(value);
if (!match) return { valid: false, reason: "format" };
const [, body, letter] = match;
const number = Number(body.replace(/^[XYZ]/, (c) => "XYZ".indexOf(c)));
const expected = LETTERS[number % 23];
return { valid: letter === expected, expected };
}
validateNifNie("12345678Z"); // { valid: true, expected: "Z" }
validateNifNie("x-1234567-l"); // { valid: true, expected: "L" }
validateNifNie("12345678A"); // { valid: false, expected: "Z" }Nous avons testé les trois extraits avec les exemples de cet article.
Les cas limites qu'on rencontre vraiment
Minuscules, espaces, points et tirets
Les gens saisissent 12.345.678-z, 12345678 z ou x1234567l. Normalisez avant de valider : majuscules et suppression des séparateurs. Puis stockez la forme normalisée (12345678Z), pas la saisie brute.
Zéros en tête
Un DNI peut commencer par zéro. Le problème survient quand la valeur passe par un tableur ou une colonne numérique : 01234567L devient 1234567L et le contrôle du format à 8 chiffres échoue. La lettre ne change pas (les zéros en tête ne modifient pas le reste), vous pouvez donc compléter par des zéros jusqu'à 8 chiffres avant de valider :
const padded = value.replace(/^(\d{1,7})([A-Z])$/, (_, n, l) => n.padStart(8, "0") + l);Ne le faites que si vous savez que la source perd les zéros ; sinon, mieux vaut refuser et demander le numéro complet.
Lettre manquante
Beaucoup d'anciens formulaires ne stockent que le numéro. Vous pouvez calculer la lettre pour l'afficher, mais ne la « complétez » pas en silence : si l'utilisateur s'est trompé d'un chiffre, vous fabriquerez un NIF valide qui n'est pas le sien.
Lettres absentes de la table
La table ne contient ni I, ni Ñ, ni O, ni U. Si l'une d'elles arrive en position de contrôle, le format est correct mais la lettre ne correspondra jamais : la validation renvoie false, comme prévu.
Autres NIF : CIF et NIF spéciaux
- Ce qu'on appelait autrefois le CIF, aujourd'hui le NIF des personnes morales et entités, a une autre structure : d'après l'Orden EHA/451/2008, une lettre indiquant la forme juridique (A sociétés anonymes, B SARL, G associations…), sept chiffres et un caractère de contrôle. Ce contrôle ne se calcule pas avec la table du DNI.
- Les étrangers sans NIE qui ont besoin d'un NIF en reçoivent un qui commence par M (Real Decreto 1065/2007, art. 20).
Le code de cet article couvre le DNI et le NIE. Pour valider aussi les CIF et les NIF spéciaux, essayez notre outil gratuit, qui détecte le type automatiquement.
Ce que la lettre ne vous dit pas
La lettre de contrôle sert à détecter les fautes de frappe : un chiffre erroné ou deux chiffres inversés. Ce n'est pas un mécanisme de sécurité :
- N'importe qui peut calculer la lettre de n'importe quel numéro. Avec un algorithme public, générer un NIF « valide » est trivial.
- Une lettre correcte ne dit pas que le numéro existe, qu'il appartient à la personne qui remplit le formulaire ni que le document est en cours de validité.
La lettre est donc un premier filtre (utile, peu coûteux, immédiat dans le formulaire), pas une vérification d'identité.
Comment fait Constaia
Dans Constaia, la lettre est l'un de plusieurs contrôles déterministes. Quand vous analysez un DNI ou un NIE, la réponse inclut le contrôle nif_check_digit, avec d'autres comme mrz_checksums (chiffres de contrôle de la MRZ) et mrz_matches_visual (la MRZ correspond aux données imprimées). Avec checks.holder.document_number, vous vérifiez aussi que le numéro lu est celui que l'utilisateur a saisi dans le formulaire.
curl https://api.constaia.com/v1/analyze \
-H "Authorization: Bearer ck_test_..." \
-F file=@nie.jpg \
-F 'options={"expect":["es_dni","es_nie"],"checks":{"not_expired":true,"holder":{"document_number":"X1234567L"}}}'Avec une clé ck_test_… et le fichier nie.jpg, vous obtenez une réponse simulée sans consommer de crédits (mode test). Gardez toutefois en tête que ni la lettre ni la MRZ ne prouvent qu'un document est authentique, et que Constaia n'est pas un système KYC biométrique.
Les validateurs NIF/NIE, MRZ et IBAN font partie du paquet open source @constaia/validators. Plus de détails dans Checks.
En résumé
- Lettre =
TRWAGMYFPDXBNJZSQVHLCKE[numéro % 23]. - Pour le NIE, remplacez X/Y/Z par 0/1/2 avant de diviser.
- Normalisez (majuscules, sans séparateurs) et surveillez les zéros en tête.
- Une lettre correcte n'exclut que les fautes de frappe.
Pour vérifier un numéro isolé, utilisez le validateur gratuit de NIF, NIE et CIF. Pour valider des documents complets, créez un compte gratuit avec 250 crédits par mois.
Sources
- 01Ministère espagnol de l'Intérieur — Calcul du chiffre de contrôle du NIF/NIE (espagnol)
- 02Dirección General de Ordenación del Juego — Calcul du chiffre de contrôle du NIF/NIE
- 03Orden EHA/451/2008 (NIF des personnes morales), BOE (espagnol)
- 04Real Decreto 1065/2007, article 20 (NIF des étrangers), BOE (espagnol)