TransWikia.com

Cómo validar una CURP de México

Stack Overflow en español Asked by Mariano on December 4, 2021

Pregunta: ¿Cómo puedo verificar que el formato de una CURP mexicana es válido?

¿Qué es la CURP?
La Clave Única de Registro de Población (CURP) es un código alfanumérico único de identidad de 18 caracteres utilizado para identificar oficialmente tanto a residentes como a ciudadanos mexicanos, expedido por el RENAPO.

La misma, se forma a partir de las letras de los nombres y apellidos, la fecha y la entidad federativa de nacimiento, y el sexo. Además, el caracter 17 es para evitar duplicados, y el último caracter es un dígito que se utiliza como detector-corrector de errores. La sintaxis está detallada en el Instructivo Normativo para la Asignación de la Clave Única de Registro de Población ?.

Contexto: Sólo me interesa validar que una clave podría ser válida. No me interesa en este punto ver si esa CURP existe o no.

Hasta ahora, sólo estoy verificando que sean 18 caracteres alfanuméricos con el regex:

/^[A-Zd]{18}$/

pero me interesa también considerar que los caracteres sean válidos, y que el dígito verificador coincida.

7 Answers

Puedes usar la libreria curp que está en NPM

npm install --save curp

Si no usas NPM agregarlo con bundle así.

<script src="https://bundle.run/curp"></script>

Ejemplo funcional:

var validarCurp = document.getElementById("validarCurp");

var validarBoton = document.getElementById("validarBoton");

validarBoton.addEventListener("click", function(evt) {
    evt.preventDefault();
    if(curp.validar(validarCurp.value)){
        alert('Es valido ')
    }else{
      alert('No es valido')
    }
});
<script src="https://bundle.run/curp"></script>
<h2 id="valida">Validar CURP</h2>

<p><strong>CURP:</strong>
<input id="validarCurp" type="text" /></p>

<p><input id="validarBoton" type="button" value="Validar" /></p>

Una alternativa más, sin utilizar javascript, validando solo el formato con la propiedad pattern, tiene el detalle que no podemos revisar el dígito verificador.

<form>
 <label for="curp">CURP:</label>
 <input id="curp" 
  type="text"
  required="true" 
  placeholder="Ingrese su CURP" 
  pattern="([A-Z]{4}([0-9]{2})(0[1-9]|1[0-2])(0[1-9]|1[0-9]|2[0-9]|3[0-1])[HM](AS|BC|BS|CC|CL|CM|CS|CH|DF|DG|GT|GR|HG|JC|MC|MN|MS|NT|NL|OC|PL|QT|QR|SP|SL|SR|TC|TS|TL|VZ|YN|ZS|NE)[A-Z]{3}[0-9A-Z]d)"
/>
  <button>Guardar</button>
</form >

Answered by Israel Perales on December 4, 2021

Muchas gracias. Esto me ayudó a crear un validador para PHP, dejo el código por si a alguien le sirve.

    function is_curp( $string = '' ){
// By @JorhelR
// TRANSFORMARMOS EN STRING EN MAYÚSCULAS RESPETANDO LAS Ñ PARA EVITAR ERRORES
        $string = mb_strtoupper($string, "UTF-8");
// EL REGEX POR @MARIANO
        $pattern = "/^([A-Z][AEIOUX][A-Z]{2}d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]d|3[01])[HM](?:AS|B[CS]|C[CLMSH]|D[FG]|G[TR]|HG|JC|M[CNS]|N[ETL]|OC|PL|Q[TR]|S[PLR]|T[CSL]|VZ|YN|ZS)[B-DF-HJ-NP-TV-Z]{3}[A-Zd])(d)$/";
        $validate = preg_match($pattern, $string, $match);
        if( $validate === false ){
// SI EL STRING NO CUMPLE CON EL PATRÓN REQUERIDO RETORNA FALSE
            return false;
        }
// ASIGNAMOS VALOR DE 0 A 36 DIVIDIENDO EL STRING EN UN ARRAY
        $ind = preg_split( '//u', '0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ', null, PREG_SPLIT_NO_EMPTY );
// REVERTIMOS EL CURP Y LE COLOCAMOS UN DÍGITO EXTRA PARA QUE EL VALOR DEL PRIMER CARACTER SEA 0 Y EL DEL PRIMER DIGITO DE LA CURP (INVERSA) SEA 1
        $vals = str_split( strrev( $match[0]."?" ) );
// ELIMINAMOS EL CARACTER ADICIONAL Y EL PRIMER DIGITO DE LA CURP (INVERSA)
        unset( $vals[0] );
        unset( $vals[1] );
        $tempSum = 0;
        foreach( $vals as $v => $d ){
// SE BUSCA EL DÍGITO DE LA CURP EN EL INDICE DE LETRAS Y SU CLAVE(VALOR) SE MULTIPLICA POR LA CLAVE(VALOR) DEL DÍGITO. TODO ESTO SE SUMA EN $tempSum
            $tempSum = (array_search( $d, $ind ) * $v)+$tempSum;
        }
// ESTO ES DE @MARIANO NO SUPE QUE ERA
        $digit = 10 - $tempSum % 10;
// SI EL DIGITO CALCULADO ES 10 ENTONCES SE REASIGNA A 0
        $digit = $digit == 10 ? 0 : $digit;
// SI EL DIGITO COINCIDE CON EL ÚLTIMO DÍGITO DE LA CURP RETORNA TRUE, DE LO CONTRARIO FALSE
        return $match[2] == $digit;
    }

Answered by Jorhel Reyes on December 4, 2021

Una API REST para validar CURP y obtener información básica de la persona. La API es Gratis (peticiones ilimitadas), Rápida (latencia de 200 ms en promedio) y Estandarizada de acuerdo a ISO. Más información usando Postman

Ejemplo de petición:

GET https://domain.com/api/curp/CAHF620818HMNLNL09?apiKey=bpT32rai

Ejemplo de respuesta exitosa:

{
    "curp": "CAHF620818HMNLNL09",
    "fatherName": "CALDERON",
    "motherName": "HINOJOSA",
    "name": "FELIPE DE JESUS",
    "gender": "1",
    "birthday": "1962-01-01T00:08:00.000Z",
    "birthState": "MX-MIC"
}

Documentación

Answered by Carlos Eduardo Sanchez Torres on December 4, 2021

Puedes validar una CURP y la información de la persona usando este API https://rapidapi.com/acrogenesis/api/curp-renapo.

Por ejemplo para usarla en php sería así:

<?php

$client = new httpClient;
$request = new httpClientRequest;

$request->setRequestUrl('https://curp-renapo.p.rapidapi.com/v1/curp/CURP_DE_TU_USUARIO');
$request->setRequestMethod('GET');

$request->setHeaders(array(
    'x-rapidapi-host' => 'curp-renapo.p.rapidapi.com',
    'x-rapidapi-key' => 'api-key'
));

$client->enqueue($request)->send();
$response = $client->getResponse();

echo $response->getBody();

Y te regresaría la información de esta forma:

{
  "curp":"CURP_DE_TU_USUARIO"
  "renapo_valid":true
  "paternal_surname":"CALDERON"
  "mothers_maiden_name":"HINOJOSA"
  "names":"FELIPE DE JESUS"
  "sex":"HOMBRE"
  "birthdate":"18/08/1962"
  "nationality":"MEXICO"
  "entity_birth":"MN"
  "probation_document":"ACTA DE NACIMIENTO"
  "probation_document_data":{
    "Entidad":"16"
    "Municipio":"053"
    "Año":"1963"
    "Número de acta":"00145"
  }
  "rfc":"RFC_DE_TU_USUARIO"
  "sat_valid":true
}

Answered by acrogenesis on December 4, 2021

Según un documento emitido por el SAT, mencionan en la página 3 el siguiente patrón de REGEX, el cual no válida el contenido, sino sólo el formato de la cadena de texto:

[A-Z][A,E,I,O,U,X][A-Z]{2}[0-9]{2}[0-1][0-9][0-3][0-9][M,H][AZ]{2}[B,C,D,F,G,H,J,K,L,M,N,Ñ,P,Q,R,S,T,V,W,X,Y,Z]{3}[0-9,AZ][0-9]

No obstante, es incorrecto en la penúltima parte [0-9,AZ] , la cual debería estar así [0-9,A-Z]

A nivel código (Java), podría quedar algo así su validación en una clase de Utilería:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Utils {

    public final static String REGEX_CURP = 
        "[A-Z][A,E,I,O,U,X][A-Z]{2}[0-9]{2}[0-1][0-9][0-3][0-9][M,H][A-Z]{2}[B,C,D,F,G,H,J,K,L,M,N,Ñ,P,Q,R,S,T,V,W,X,Y,Z]{3}[0-9,A-Z][0-9]";

    public static boolean validarCurp(String textoCurp){
        boolean curpValido = false;

        Pattern pattern = Pattern.compile(REGEX_CURP;
        Matcher matcher = pattern.matcher(textoCurp);
        curpValido = matcher.find();

        matcher = null;
        pattern = null;

        return curpValido;
    }
}

Answered by Nekio on December 4, 2021

Un poco tarde mi respuesta, pero hace tiempo hice este método para validar los RFC, tanto para personas físicas como personas morales. Los regex los saqué del sitio oficial del SAT para validar RFC. Espero a alguien le sirva. La función está hecha en JS

function validateRFC(rfc) {

        var patternPM = "^(([A-ZÑ&]{3})([0-9]{2})([0][13578]|[1][02])(([0][1-9]|[12][\d])|[3][01])([A-Z0-9]{3}))|" +
            "(([A-ZÑ&]{3})([0-9]{2})([0][13456789]|[1][012])(([0][1-9]|[12][\d])|[3][0])([A-Z0-9]{3}))|" +
            "(([A-ZÑ&]{3})([02468][048]|[13579][26])[0][2]([0][1-9]|[12][\d])([A-Z0-9]{3}))|" +
            "(([A-ZÑ&]{3})([0-9]{2})[0][2]([0][1-9]|[1][0-9]|[2][0-8])([A-Z0-9]{3}))$";
        var patternPF = "^(([A-ZÑ&]{4})([0-9]{2})([0][13578]|[1][02])(([0][1-9]|[12][\d])|[3][01])([A-Z0-9]{3}))|" +
            "(([A-ZÑ&]{4})([0-9]{2})([0][13456789]|[1][012])(([0][1-9]|[12][\d])|[3][0])([A-Z0-9]{3}))|" +
            "(([A-ZÑ&]{4})([02468][048]|[13579][26])[0][2]([0][1-9]|[12][\d])([A-Z0-9]{3}))|" +
            "(([A-ZÑ&]{4})([0-9]{2})[0][2]([0][1-9]|[1][0-9]|[2][0-8])([A-Z0-9]{3}))$";

        if (rfc.match(patternPM) || rfc.match(patternPF)) {
            return true;
        } else {
            alert("La estructura de la clave de RFC es incorrecta.");
            return false;
        }
    }

Answered by ArCiGo on December 4, 2021

Expresión regular

La siguiente expresión regular verifica:

  • Las posiciones donde se esperan letras, vocales y consonantes de los nombres y apellidos.
  • Fecha válida (aunque para simplificarlo, no se están validando meses con menos de 31 días).
  • Listado válido de entidades federativas.
  • Y genera referencias para separar los primeros 17 dígitos (grupo 1) del último dígito (grupo 2).
/^([A-Z][AEIOUX][A-Z]{2}d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]d|3[01])[HM](?:AS|B[CS]|C[CLMSH]|D[FG]|G[TR]|HG|JC|M[CNS]|N[ETL]|OC|PL|Q[TR]|S[PLR]|T[CSL]|VZ|YN|ZS)[B-DF-HJ-NP-TV-Z]{3}[A-Zd])(d)$/


Validación completa

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

//Función para validar una CURP
function curpValida(curp) {
    var re = /^([A-Z][AEIOUX][A-Z]{2}d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]d|3[01])[HM](?:AS|B[CS]|C[CLMSH]|D[FG]|G[TR]|HG|JC|M[CNS]|N[ETL]|OC|PL|Q[TR]|S[PLR]|T[CSL]|VZ|YN|ZS)[B-DF-HJ-NP-TV-Z]{3}[A-Zd])(d)$/,
        validado = curp.match(re);
	
    if (!validado)  //Coincide con el formato general?
    	return false;
    
    //Validar que coincida el dígito verificador
    function digitoVerificador(curp17) {
        //Fuente https://consultas.curp.gob.mx/CurpSP/
        var diccionario  = "0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ",
            lngSuma      = 0.0,
            lngDigito    = 0.0;
        for(var i=0; i<17; i++)
            lngSuma = lngSuma + diccionario.indexOf(curp17.charAt(i)) * (18 - i);
        lngDigito = 10 - lngSuma % 10;
        if (lngDigito == 10) return 0;
        return lngDigito;
    }
  
    if (validado[2] != digitoVerificador(validado[1])) 
    	return false;
        
    return true; //Validado
}


//Handler para el evento cuando cambia el input
//Lleva la CURP a mayúsculas para validarlo
function validarInput(input) {
    var curp = input.value.toUpperCase(),
        resultado = document.getElementById("resultado"),
        valido = "No válido";
        
    if (curpValida(curp)) { // ⬅️ Acá se comprueba
    	valido = "Válido";
        resultado.classList.add("ok");
    } else {
    	resultado.classList.remove("ok");
    }
        
    resultado.innerText = "CURP: " + curp + "nFormato: " + valido;
}
#resultado {
    background-color: red;
    color: white;
    font-weight: bold;
}
#resultado.ok {
    background-color: green;
}
<label>CURP:
    <input type="text" id="curp_input" oninput="validarInput(this)" style="width:100%;" placeholder="Ingrese su CURP">
</label>
<pre id="resultado"></pre>


Descripción

Tomando en cuenta la estructura con la que se forma una CURP:

Descripción de cómo se forma cada caracter

  • El primer caracter es la inicial del primer apellido [A-Z]
    (si fuese otra letra, se usa una X).
  • Seguido por la primera vocal interna del apellido [AEIOUX]
    (o una X si no tuviese).
  • Y las iniciales del segundo apellido y del nombre [A-Z]{2}
  • La fecha de nacimiento.
    • d{2} año.
    • (?:0[1-9]|1[0-2]) mes.
    • (?:0[1-9]|[12]d|3[01]) día.
  • El sexo (Hombre o Mujer) [HM]
  • La entidad federativa en la que nació (listadas en el pdf)
    (?:AS|B[CS]|C[CLMSH]|D[FG]|G[TR]|HG|JC|M[CNS]|N[ETL]|OC|PL|Q[TR]|S[PLR]|T[CSL]|VZ|YN|ZS)
  • Las primeras consonantes internas de apellidos y nombre [B-DF-HJ-NP-TV-Z]{3}
  • La homoclave (homonimia y siglo) [A-Zd]
  • El dígito verificador (capturado en el grupo 2) (d)


Luego de ver si coincide con el regex, comprobamos que el dígito verificador sea válido. Es decir, si coincide con el calculado de los primeros 17 caracteres:

if (validado[2] != digitoVerificador(validado[1]))

Para calcular el digito, primero se suma el valor de cada uno de los 17 caracteres, los cuales tienen un valor de 0 a 36 según este orden (diccionario):

0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ
for(var i=0; i<17; i++)
    lngSuma = lngSuma + diccionario.indexOf(curp17.charAt(i)) * (18 - i);

Y se toma el complemento a 10 del último dígito de esta suma (o 0 si da 10).

lngDigito = 10 - lngSuma % 10;
if (lngDigito == 10) return 0;
return lngDigito;

Answered by Mariano on December 4, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP