Skip to content

Instantly share code, notes, and snippets.

@afgomez
Last active May 5, 2024 12:31
Show Gist options
  • Star 54 You must be signed in to star a gist
  • Fork 24 You must be signed in to fork a gist
  • Save afgomez/5691823 to your computer and use it in GitHub Desktop.
Save afgomez/5691823 to your computer and use it in GitHub Desktop.
Spanish DNI, CIF, NIE validator
/**
* ValidateSpanishID. Returns the type of document and checks its validity.
*
* Usage:
* ValidateSpanishID( str );
*
* > ValidateSpanishID( '12345678Z' );
* // { type: 'dni', valid: true }
*
* > ValidateSpanishID( 'B83375575' );
* // { type: 'cif', valid: false }
*
* The algorithm is adapted from other solutions found at:
* - http://www.compartecodigo.com/javascript/validar-nif-cif-nie-segun-ley-vigente-31.html
* - http://es.wikipedia.org/wiki/C%C3%B3digo_de_identificaci%C3%B3n_fiscal
*/
ValidateSpanishID = (function() {
'use strict';
var DNI_REGEX = /^(\d{8})([A-Z])$/;
var CIF_REGEX = /^([ABCDEFGHJKLMNPQRSUVW])(\d{7})([0-9A-J])$/;
var NIE_REGEX = /^[XYZ]\d{7,8}[A-Z]$/;
var ValidateSpanishID = function( str ) {
// Ensure upcase and remove whitespace
str = str.toUpperCase().replace(/\s/, '');
var valid = false;
var type = spainIdType( str );
switch (type) {
case 'dni':
valid = validDNI( str );
break;
case 'nie':
valid = validNIE( str );
break;
case 'cif':
valid = validCIF( str );
break;
}
return {
type: type,
valid: valid
};
};
var spainIdType = function( str ) {
if ( str.match( DNI_REGEX ) ) {
return 'dni';
}
if ( str.match( CIF_REGEX ) ) {
return 'cif';
}
if ( str.match( NIE_REGEX ) ) {
return 'nie';
}
};
var validDNI = function( dni ) {
var dni_letters = "TRWAGMYFPDXBNJZSQVHLCKE";
var letter = dni_letters.charAt( parseInt( dni, 10 ) % 23 );
return letter == dni.charAt(8);
};
var validNIE = function( nie ) {
// Change the initial letter for the corresponding number and validate as DNI
var nie_prefix = nie.charAt( 0 );
switch (nie_prefix) {
case 'X': nie_prefix = 0; break;
case 'Y': nie_prefix = 1; break;
case 'Z': nie_prefix = 2; break;
}
return validDNI( nie_prefix + nie.substr(1) );
};
var validCIF = function( cif ) {
var match = cif.match( CIF_REGEX );
var letter = match[1],
number = match[2],
control = match[3];
var even_sum = 0;
var odd_sum = 0;
var n;
for ( var i = 0; i < number.length; i++) {
n = parseInt( number[i], 10 );
// Odd positions (Even index equals to odd position. i=0 equals first position)
if ( i % 2 === 0 ) {
// Odd positions are multiplied first.
n *= 2;
// If the multiplication is bigger than 10 we need to adjust
odd_sum += n < 10 ? n : n - 9;
// Even positions
// Just sum them
} else {
even_sum += n;
}
}
var control_digit = (10 - (even_sum + odd_sum).toString().substr(-1) );
var control_letter = 'JABCDEFGHI'.substr( control_digit, 1 );
// Control must be a digit
if ( letter.match( /[ABEH]/ ) ) {
return control == control_digit;
// Control must be a letter
} else if ( letter.match( /[KPQS]/ ) ) {
return control == control_letter;
// Can be either
} else {
return control == control_digit || control == control_letter;
}
};
return ValidateSpanishID;
})();
@jordigarciad
Copy link

He probado con el NIF K0867756N despues de aplicar la corrección y sigue sin funcionar.

Parece que no identifica los DNI "Españoles residentes menores 14 años sin DNI (NIF K)"
Adjunto enlace de la Agencia Tributaria:
https://www.agenciatributaria.es/AEAT.internet/Inicio/La_Agencia_Tributaria/Campanas/_Campanas_/Fiscalidad_de_no_residentes/_Identificacion_/Preguntas_frecuentes_sobre_obtencion_de_NIF_de_no_Residentes/_Que_tipos_de_NIF_de_personas_fisicas_utiliza_la_normativa_tributaria_espanola_.shtml

@HectorLS
Copy link

He probado actualmente con 4 CIF existentes y no me valida ninguno como true

@qwertyllo
Copy link

Los problemas con CIFs que no validan (ejemplo "B72327000") se solucionan haciendo el módulo 10 para calcular el dígito de control.

Es decir, cambiar:

var control_digit = (10 - (even_sum + odd_sum).toString().substr(-1) );

Por:

var control_digit = (10 - (even_sum + odd_sum).toString().substr(-1) ) % 10;

@pookdeveloper
Copy link

En el replace faltaría añadir /g para que cambie todas ocurrecias:

str.toUpperCase().replace(/\s, '').replace('-', '');
str.toUpperCase().replace(/\s/g, '').replace('-', '');

@kylety1990
Copy link

Hola trabajo con Angular, me gustaría saber si tenéis algún validator form con este método. Gracias de antemano.

@Juanpalacios08
Copy link

Buenas. Los CIF de organizaciones públicas que acaban en letra L no pasan por esta validación ¿no?

@alphp
Copy link

alphp commented May 5, 2024

He encontrado un validador de TIN (aka NIF) que valida TIN de prácticamente toda Europa:
https://github.com/loophp/tin
Sin embargo no calcula bien los NIF de empresas y de personas que no tengan DNI o NIE.
Así que he creado una PR para solucionarlo:
loophp/tin#36
Sin embargo no he podido aportar referencias oficiales al algoritmo de validación (solo una explicación de la Junta de Andalucía) y parece que tienen la PR en espera (no se de qué, la verdad).
Si pudierais dar apoyo para que incluyan la PR sería genial.
Por cierto, el código de la PR está basado en el que ya publiqué aquí:
https://lab.fawno.com/2015/08/27/validacion-de-cif-nif/
Y que incluí en este otro proyecto:
https://github.com/fawno/AEAT

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment