Regex Argentine CUIT (tax identifier)
A CUIT (or CUIL) has 11 digits, written '20-05536168-2': a 2-digit prefix, 8 digits (the DNI or company number, zero-padded if needed) and a modulo 11 check digit with weights 5 4 3 2 7 6 5 4 3 2. Common prefixes are 20, 23, 24 and 27 for individuals, 30, 33 and 34 for companies. The three patterns read here do not all check the prefix: validator.js does but is unanchored and ignores hyphens, django-localflavor and afip-cuit-validator accept any two digits. Here's an anchored pattern bounding the prefix and requiring both separators to be either present or absent, compared against those attempts.
/^(?:20|23|24|27|30|33|34)(-?)[0-9]{8}\1[0-9]$/passes 24/24 cases
Comparison of existing patterns
| Source | pattern | Score on the corpus | ReDoS |
|---|---|---|---|
| validator.js isTaxID('es-AR') — préfixe contrôlé mais aucune ancre : « X20055361682Y » passe, et les tirets ne sont pas gérés (« 20-05536168-2 » refusé) | (20|23|24|27|30|33|34)[0-9]{8}[0-9] | 16 / 24 | safe |
| django-localflavor (ar/forms.py) — n'importe quel préfixe (« 99-05536168-2 » passe), tirets indépendants (« 20-055361682 » passe) ; le type est contrôlé ensuite dans le code | ^\d{2}-?\d{8}-?\d$ | 20 / 24 | safe |
| afip-cuit-validator (npm) — deux regex en OU : n'importe quel préfixe, et la forme avec tirets doit être complète ; « 99-05536168-2 » et « 99055361682 » passent | ^\d{2}\-\d{8}\-\d{1}$|^\d{11}$ | 22 / 24 | safe |
Implementation
const re = new RegExp("^(?:20|23|24|27|30|33|34)(-?)[0-9]{8}\\1[0-9]$", "");
re.test(input);Limits
- Valide seulement la FORME : ne calcule pas la clé modulo 11. « 20-05536168-3 » a la bonne forme mais une clé fausse et passe ce motif. Ni l'existence du contribuable, ni la cohérence avec le DNI ne sont contrôlées.
- Les préfixes ne font pas consensus : Wikipédia cite aussi 25 et 26, python-stdnum accepte 50, 51 et 55 (usages internationaux). Le motif ne retient que les sept préfixes communs aux implémentations lues ; ajoutez les autres si votre cas l'exige.
- Quand le calcul donne 10, la clé n'est pas attribuée telle quelle (le préfixe est alors remplacé, d'après Wikipédia) ; validator.js et python-stdnum, eux, convertissent 10 en 9. Aucune regex ne peut tester cela.
- Le CUIT d'une personne physique contient son numéro de DNI : c'est une donnée personnelle. N'utilisez que des exemples de documentation ou synthétiques, comme ceux du corpus.