Regex Romanian CNP (cod numeric personal)
The CNP has 13 digits: S (sex and century: 1-2 for 1900-1999, 3-4 for 1800-1899, 5-6 for 2000-2099, 7-8 for resident foreigners, 9 for other foreigners), YYMMDD the birth date, CC the county code (01 to 47, 51 and 52, per the DG TAXUD specification), NNN a serial number and K a key. For S = 9 the DG TAXUD document describes a '9000…' form with no date. The four real attempts I read stop at '13 digits' or a first digit 1-9, bounding neither month, day nor county: '1991399999990' passes. The key (weights 279146358279, modulo 11, 10 gives 1) comes from secondary sources: the DG TAXUD specification states the algorithm is not public.
/^(?:[1-8]\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])(?:0[1-9]|[1-3]\d|4[0-7]|5[12])\d{4}|9000\d{9})$/passes 25/25 cases
Comparison of existing patterns
Implementation
const re = new RegExp("^(?:[1-8]\\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\\d|3[01])(?:0[1-9]|[1-3]\\d|4[0-7]|5[12])\\d{4}|9000\\d{9})$", "");
re.test(input);Limits
- Valide la forme (sexe/siècle, mois, jour, département) mais PAS la clé : « 1630615123458 » passe. Complément : clé = (Σ chiffre[i] × poids[i] pour les 12 premiers, poids 2, 7, 9, 1, 4, 6, 3, 5, 8, 2, 7, 9) % 11, remplacé par 1 si le reste vaut 10. Cet algorithme vient de python-stdnum et de cnp-spec (secondaires) ; la spécification DG TAXUD le déclare non public.
- Le jour 31 est accepté pour tous les mois et la date n'est pas confrontée à aujourd'hui. Le département est borné d'après la spécification DG TAXUD (01-47, 51, 52) ; python-stdnum accepte aussi 48, 70 et 80-83 (étrangers) : élargissez la classe si nécessaire. La forme « 9000… » est tirée d'un tableau du document dont l'exemple a 12 caractères.
- Le jour du siècle codé par S n'est pas recoupé avec l'année (S = 5 ou 6 pour 2000-2099, S = 1 ou 2 pour 1900-1999). Le CNP est une donnée personnelle : n'utilisez que des numéros d'exemple ou synthétiques à date de naissance future.