Rexact
Cheatsheet

Regex numéro de TVA espagnol (NIF, CIF, NIE)

Le numéro de TVA espagnol est le NIF de l'assujetti précédé de « ES » : 9 caractères où le premier, le dernier, ou les deux sont des lettres. La FAQ VIES de la Commission le décrit ainsi : « le premier et le dernier caractère peuvent être alphabétiques ou numériques, mais pas tous les deux numériques ». Concrètement, une société a un CIF (lettre, 7 chiffres, clé chiffre ou lettre), une personne physique un DNI (8 chiffres et une lettre) ou un NIE (X, Y ou Z, 7 chiffres, une lettre). Les tentatives relues divergent : la version publiée de validator.js refuse les CIF à clé chiffre et accepte « _ » en tête, sa version de développement refuse les personnes physiques, valvat et jsvat acceptent n'importe quelle lettre initiale (I et O comprises), et la regex du Regular Expressions Cookbook accepte 9 chiffres. Voici un motif qui suit la règle de la Commission et exclut les lettres I, O et T en tête, comparé à ces tentatives.

/^ES(?:[0-9]{8}[A-Z]|[A-HJ-NP-SU-Z][0-9]{7}[0-9A-Z])$/
passe 31/31 cas

Comparatif des patterns existants

SourcepatternScore sur le corpusReDoS
validator.js 13.15.35 publié sur npm (lib/isVAT.js) — « wd{7}[A-Z] » : refuse tous les CIF à clé chiffre (« ESB58378431 », « ESA12345674 »), accepte « ESI1234567A » et « ES_1234567A », préfixe facultatif^(ES)?\w\d{7}[A-Z]$24 / 31sûr
validator.js, branche master (src/lib/isVAT.js) — ne couvre que les sociétés (CIF) : refuse DNI, NIE et K/L/M (« ES54362315K », « ESX5253868R »), impose le type de clé par lettre initiale ; préfixe « ES » facultatif (« B64717838 » nu passe)^(ES)?(?:[ABEH]\d{8}|[NPQRSW]\d{7}[A-J]|[CDFGJUV]\d{7}[0-9A-J])$22 / 31sûr
valvat (syntax.rb, A et Z remplacés par ^ et $) — ancrée, couvre CIF, DNI et NIE ; mais « ESO12345678 » et « ESI1234567A » passent : lettre initiale libre^ES([A-Z][0-9]{8}|[0-9]{8}[A-Z]|[A-Z][0-9]{7}[A-Z])$29 / 31sûr
jsvat (spain.ts) — les quatre regex de l'objet rules.regex réunies par « | » ; la lettre initiale du CIF numérique est libre (« ESO12345678 » passe) ; les clés sont contrôlées à part par calcFn^(ES)([A-Z]\d{8})$|^(ES)([A-HN-SW]\d{7}[A-J])$|^(ES)([0-9YZ]\d{7}[A-Z])$|^(ES)([KLMX]\d{7}[A-Z])$30 / 31sûr
Regular Expressions Cookbook, recette 4.21 (27 pays en une regex, insensible à la casse) — branche espagnole « (ES)?[0-9A-Z][0-9]{7}[0-9A-Z] » : accepte 9 chiffres (« ES123456789 »), les minuscules et un préfixe absent^((AT)?U[0-9]{8}|(BE)?0[0-9]{9}|(BG)?[0-9]{9,10}|(CY)?[0-9]{8}L|(CZ)?[0-9]{8,10}|(DE)?[0-9]{9}|(DK)?[0-9]{8}|(EE)?[0-9]{9}|(EL|GR)?[0-9]{9}|(ES)?[0-9A-Z][0-9]{7}[0-9A-Z]|(FI)?[0-9]{8}|(FR)?[0-9A-Z]{2}[0-9]{9}|(GB)?([0-9]{9}([0-9]{3})?|[A-Z]{2}[0-9]{3})|(HU)?[0-9]{8}|(IE)?[0-9]S[0-9]{5}L|(IT)?[0-9]{11}|(LT)?([0-9]{9}|[0-9]{12})|(LU)?[0-9]{8}|(LV)?[0-9]{11}|(MT)?[0-9]{8}|(NL)?[0-9]{9}B[0-9]{2}|(PL)?[0-9]{10}|(PT)?[0-9]{9}|(RO)?[0-9]{2,10}|(SE)?[0-9]{12}|(SI)?[0-9]{8}|(SK)?[0-9]{10})$26 / 31sûr

Implémentation

const re = new RegExp("^ES(?:[0-9]{8}[A-Z]|[A-HJ-NP-SU-Z][0-9]{7}[0-9A-Z])$", "");
re.test(input);

Limites

  • Valide seulement la FORME : « ESB64717839 » et « ES12345678A » ont la bonne structure mais une clé fausse (lettre DNI modulo 23, clé CIF de type Luhn) et passent ce motif. La clé n'est pas recalculée.
  • Le motif accepte une clé lettre ou chiffre pour toute forme juridique, car python-stdnum signale des informations contradictoires selon la forme ; validator.js (version de développement) impose au contraire un type de clé par lettre initiale.
  • Les lettres initiales exclues (I, O, T) viennent de python-stdnum, pas de la FAQ de la Commission. Les formes K, L, M (personnes sans NIE) et X, Y, Z (NIE) sont acceptées : voir dni-nie-espagnol pour les identifiants de personnes physiques.
  • Aucune vérification d'existence (VIES). Pas de tolérance pour espaces, tirets ou minuscules : normalisez avant validation. Les numéros du corpus sont des exemples de documentation ou synthétiques.

Pages liées