Skip to content

Instantly share code, notes, and snippets.

@afgomez
Last active December 9, 2023 18:12
Show Gist options
  • Star 53 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;
})();
@albciff
Copy link

albciff commented Sep 20, 2018

Este control es correcto según la definición de wikipedia https://es.wikipedia.org/wiki/C%C3%B3digo_de_identificaci%C3%B3n_fiscal donde indica que los CIFs que empiezan por A|B|E|H el digito de control debe ser un número.

    // Control must be a digit
    if ( letter.match( /[ABEH]/ ) ) {
      return control == control_digit;

Recientemente pero me han passado CIFs validos que empezando por E y por A tienen letra de control... y son validos, p.e E9729353D. Alguien sabe donde encontrar la especificación oficial sobre el calculo del digito/letra de control?

@tompare
Copy link

tompare commented Jan 21, 2019

Los NIF terminados en 0 siempre dan error, como @uiktiomasfeliz y @gtamborero indican. Eso es porque hay un error con la comprobación de éste. El enlace de wikipedia ( código de identificación fical ) dice que el código de verificación debe ser 10 - el último dígito de C, pero si C termina en 0, éste debe ser 0.

He modificado el código para sacar el control digit. Quedaría así:

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

De este modo lo que hago es obtener el último dígito de dicha resta, por lo que si hacemos 10-0, el resultado del código sería 0.

@jordigarciad
Copy link

No valida bien NIF del tipo K
K0867756N

Aquí lo valida bien:
https://comunidadhorizontal.com/utiles/validar-cif-nif-nie/

He mirado el código y no lo reconoce de ninguno de los 3 type (DNI, CIF, NIE), pues la expresión regular de CIF no lo contempla:
([ABCDEFGHJKLMNPQRSUVW])(\d{7})([0-9A-J])
Veo que sólo permite letra final hasta J y en mi ejemplo tengo una N y es un NIF válido...

@jvmonjo
Copy link

jvmonjo commented Oct 24, 2019

@afgomez Gracias por crear este gist. Lo he adaptado, he corregido la validación del CIF y lo he empaquetado como una pequeña librería en npm:
https://github.com/jvmonjo/spain-id

@carlos-mg89
Copy link

La corrección de @tompare está bien. Lo puedo confirmar al menos con un CIF de una SL (empiezan por B).

Aquí publico el gist con la corrección del dígito de control de @tompare:
https://gist.github.com/carlos-mg89/4aaafa310c9e4b91f5fb890540f38cae

@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?

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