Skip to content

Instantly share code, notes, and snippets.

@afgomez
Last active April 22, 2024 07:08
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;
})();
@dizapico
Copy link

dizapico commented Jun 2, 2013

Has mantenido los if de la 53-61 en mi fork te puse else if, realmente no cambia NADA, pero si me parece mas comodo al leerlo no?

@skarcha
Copy link

skarcha commented Jul 30, 2014

Lo primero, muchísimas gracias por compartir la función.

Ahora te comento que hay un error en la línea 116. Sólo hay que restar a 10 si el último dígito es mayor 0, si no, el dígito de control sería 10, y por tanto falla la validación.

@StarpTech
Copy link

// Ensure upcase and remove whitespace and hyphen notation
str = str.toUpperCase().replace(/\s/, '').replace(/\-/, '').replace(/\-/, '');`

top support other valid id notations like in http://formvalidation.io/validators/id/

Thanks for your effort!

@gtamborero
Copy link

Funciona perfecto! Gracias :)
Lo uso dentro de VUEjs dentro de metodos:
nifControl(){ if (this.inputData.length >= 9) { if (!(this.showError = !ValidateSpanishID(this.inputData).valid)){ this.$emit("dataChange", this.inputData); } } }

@uiktiomasfeliz
Copy link

Todo funcionaba bien, hasta que le pasaron este CIF 'B72327000'. Resulta que el programa lo detecta como falso, aunque varios sitios online lo da por válido.

@gtamborero
Copy link

Parece que funciona bien en general pero este nif falla y es valido: B67197210

@TORR3S
Copy link

TORR3S commented Apr 11, 2018

Con mi código no falla ninguno de esos números:
https://github.com/TORR3S/Check-NIF

@pezzz
Copy link

pezzz commented May 21, 2018

Hi,

As I can see in NIE_REGEX: there are two options available: with 7 and 8 digits. Is NIE with 8 digits still supported in Spain and still is a valid format?

@danielart
Copy link

yes @pezzz, NIE with 8 digits is still valid at the moment

@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