10

Pregunta: ¿Cómo puedo verificar que el formato de un NSS mexicano sea válido?

¿Qué es el NSS? El Número de Seguridad Social (NSS) es la identidad social del trabajador. Es expedido por el IMSS y se conforma por 11 dígitos.

Contexto: Quiero validar que un NSS podría ser válido. No me interesa ver si efectivamente existe. Actualmente estoy validando que sean 11 dígitos:

/^\d{11}$/

pero ahora me interesa ver si se puede validar de forma más estricta.

Mariano
  • 23,777
  • 20
  • 70
  • 102
  • Relacionado: [Cómo validar una CURP de México](http://es.stackoverflow.com/q/31039/127) – Mariano Nov 05 '16 at 13:19
  • Relacionado: [Cómo validar un RFC de México y su digito verificador](http://es.stackoverflow.com/q/31713/127) – Mariano Nov 05 '16 at 13:19

1 Answers1

16

Formato del NSS

El Número de Seguridad Social se constituye por:

2 subdelegación IMSS + 2 año alta + 2 año nacimiento + 4 código persona + 1 dígito verificador

Los códigos de Subdelegaciones del IMSS están listados en el Manual para Integración del NSS . Si bien algunos (pocos) números no son válidos, podrían serlo en el futuro, por lo que no podemos validar por ese campo. Además, en los casos especiales cuando no se posee un registro de fecha de nacimiento, se utiliza el código 97.

Cuando se posee una fecha de nacimiento, logicamente debe ser menor al año de alta del trabajador.

El dígito verificador es asignado utilizando el algoritmo de Luhn, lo cual nos permitirá realizar la validación del NSS.


Expresión regular

Sólo se validará que sean 11 dígitos, pero usaremos la expresión para capturar los primeros 3 campos por separado:

/^(\d{2})(\d{2})(\d{2})\d{5}$/


Validación Completa

Publico el código en JavaScript para poder ejecutarlo acá, pero es muy sencillo de llevar a cualquier otro lenguaje.

// Devuelve un booleano si es un NSS válido
// (deben ser 11 dígitos sin otro caracter en el medio)
function nssValido(nss) {
    const re       = /^(\d{2})(\d{2})(\d{2})\d{5}$/,
          validado = nss.match(re);
        
    if (!validado)  // 11 dígitos y subdelegación válida?
        return false;
        
    const subDeleg = parseInt(validado[1],10),
          anno     = new Date().getFullYear() % 100;
    var   annoAlta = parseInt(validado[2],10),
          annoNac  = parseInt(validado[3],10);
    
    //Comparar años (excepto que no tenga año de nacimiento)
    if (subDeleg != 97) {
        if (annoAlta <= anno) annoAlta += 100;
        if (annoNac  <= anno) annoNac  += 100;
        if (annoNac  >  annoAlta)
         return false; // Err: se dio de alta antes de nacer!
    }
    
    return luhn(nss);
}

// Algoritmo de Luhn
//  https://es.wikipedia.org/wiki/Algoritmo_de_Luhn
function luhn(nss) {
    var suma   = 0,
        par    = false,
        digito;
    
    for (var i = nss.length - 1; i >= 0; i--) {
        var digito = parseInt(nss.charAt(i),10);
        if (par)
         if ((digito *= 2) > 9)
             digito -= 9;
        
        par = !par;
        suma += digito;
    }
    return (suma % 10) == 0;
}


//Handler para el evento cuando cambia el input
//Elimina cualquier caracter no numérico y comprueba validez
function validarInput(input) {
    var nss       = input.value.replace(/\D+/g,""),
        resultado = document.getElementById("resultado"),
        valido;
        
    if (nssValido(nss)) { // ⬅️ Acá se comprueba
     valido = "Válido";
        resultado.classList.add("ok");
    } else {
        valido   = "No válido";
     resultado.classList.remove("ok");
    }
        
    resultado.innerText = "NSS: " + nss + "\nFormato: " + valido;
}
#resultado {
    background-color: red;
    color: white;
    font-weight: bold;
}
#resultado.ok {
    background-color: green;
}
<label>NSS:</label>
<input type="text" id="nss_input" style="width:100%;"
       oninput="validarInput(this)"
       placeholder="Ingrese su NSS">
<pre id="resultado"></pre>


Descripción

Luego de validar que son 11 dígitos y haber separado los 3 primeros campos, se compara que el año de nacimiento sea previo al de inscripción. Como sólo contamos con los últimos dígitos del año, se agrega 100 al número si es menor al año actual (así '05 será mayor a '99 por ejemplo).

if (subDeleg != 97) {   // Si tiene año de nacimiento
    if (annoAlta <= anno) annoAlta += 100;
    if (annoNac  <= anno) annoNac  += 100;
    if (annoNac  >  annoAlta)
        return false; // Err: se dio de alta antes de nacer!
}

Sin embargo, la principal validación es por el algoritmo de Luhn, que consta en tomar los dígitos en posiciones impares, y los dígitos en posiciones pares multiplicados por 2. Se suman todos los dígitos (si alguno de estos fuese mayor o igual a 10 se toma la suma de cada dígito).

var digito = parseInt(nss.charAt(i),10);
if (par)
    if ((digito *= 2) > 9)
        digito -= 9;


Un NSS es válido si el último dígito de esa suma da 0.

return (suma % 10) == 0;
Mariano
  • 23,777
  • 20
  • 70
  • 102