Regex - ¿Cómo Validar Un RFC De México Y Su Digito Verificador?
Có thể bạn quan tâm
Expresión regular
La siguiente expresión regular verifica:
- Los primeros 3 (persona moral) o 4 (persona física) caracteres en mayúsculas.
- Fecha válida (aunque para simplificarlo, no se están validando meses con menos de 31 días).
- El dígito verificador sea un dígito o una letra A.
- Permitiendo que haya guiones y/o espacios entre las partes.
- Capturando cada parte en un grupo.
Validación completa
Publico el código en JavaScript para poder correrlo acá, pero es muy sencillo de llevar a cualquier otro lenguaje.
//Función para validar un RFC // Devuelve el RFC sin espacios ni guiones si es correcto // Devuelve false si es inválido // (debe estar en mayúsculas, guiones y espacios intermedios opcionales) function rfcValido(rfc, aceptarGenerico = true) { const re = /^([A-ZÑ&]{3,4}) ?(?:- ?)?(\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])) ?(?:- ?)?([A-Z\d]{2})([A\d])$/; var validado = rfc.match(re); if (!validado) //Coincide con el formato general del regex? return false; //Separar el dígito verificador del resto del RFC const digitoVerificador = validado.pop(), rfcSinDigito = validado.slice(1).join(''), len = rfcSinDigito.length, //Obtener el digito esperado diccionario = "0123456789ABCDEFGHIJKLMN&OPQRSTUVWXYZ Ñ", indice = len + 1; var suma, digitoEsperado; if (len == 12) suma = 0 else suma = 481; //Ajuste para persona moral for(var i=0; i<len; i++) suma += diccionario.indexOf(rfcSinDigito.charAt(i)) * (indice - i); digitoEsperado = 11 - suma % 11; if (digitoEsperado == 11) digitoEsperado = 0; else if (digitoEsperado == 10) digitoEsperado = "A"; //El dígito verificador coincide con el esperado? // o es un RFC Genérico (ventas a público general)? if ((digitoVerificador != digitoEsperado) && (!aceptarGenerico || rfcSinDigito + digitoVerificador != "XAXX010101000")) return false; else if (!aceptarGenerico && rfcSinDigito + digitoVerificador == "XEXX010101000") return false; return rfcSinDigito + digitoVerificador; } //Handler para el evento cuando cambia el input // -Lleva la RFC a mayúsculas para validarlo // -Elimina los espacios que pueda tener antes o después function validarInput(input) { var rfc = input.value.trim().toUpperCase(), resultado = document.getElementById("resultado"), valido; var rfcCorrecto = rfcValido(rfc); // ⬅️ Acá se comprueba if (rfcCorrecto) { valido = "Válido"; resultado.classList.add("ok"); } else { valido = "No válido" resultado.classList.remove("ok"); } resultado.innerText = "RFC: " + rfc + "\nResultado: " + rfcCorrecto + "\nFormato: " + valido; } #resultado { background-color: red; color: white; font-weight: bold; } #resultado.ok { background-color: green; } <label>RFC:</label> <input type="text" id="rfc_input" style="width:100%;" oninput="validarInput(this)" placeholder="Ingrese su RFC"> <pre id="resultado"></pre>
Descripción
Tomando como referencia la forma en que se construye el RFC:
- Los primeros 3-4 caracteres se toman del nombre ([A-ZÑ&]{3,4}) Grupo 1.
- Inicial del apellido paterno (o primera inicial de la empresa).
- Primera vocal interna del apellido paterno (o segunda inicial de la empresa). * En este caso, podríamos haber validado que sea sólo una vocal o una "X", pero si el primer apellido tiene 1 o 2 letras, se toma la primera letra del apellido materno (puede ser una consonante). * Para las empresas, si no tienen 3 palabras, se toman las siguientes letras del primer nombre.
- Inicial del apellido materno (o tercera inicial de la empresa).
- Inicial del nombre (nada para empresas, tienen 3 caracteres en total).
- Espacios o guiones opcionales ?(?:- ?)?. Acepta: " ", "-", " -", " - ", "- ", o sin guiones ni espacios. * El patrón se ve gracioso pero es: un espacio opcional, seguido de un grupo opcional (sin capturar), éste coincide con un guión seguido opcionalmente de un espacio. Si no se quiere permitir espacios ni guiones, se puede eliminar este patrón.
- La fecha de nacimiento (o de creación de la empresa). (\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])) Grupo 2.
- \d{2} año.
- (?:0[1-9]|1[0-2]) mes.
- (?:0[1-9]|[12]\d|3[01]) día. * Estoy aceptando hasta 31 para cualquier mes. Considero que un error al ingresar los datos de la fecha se validaría más adelante con el dígito verificador. No obstante, si se quisiera ser más estricto, y aunque se podría validar en la expresión regular, recomendaría hacerlo con las funciones del lenguaje de programación utilizado.
- Espacios o guiones opcionales ?(?:- ?)?.
- Homoclave de 2 caracteres alfanuméricos ([A-Z\d]{2}) Grupo 3.
- Dígito verificador (dígito o letra A) ([A\d]) Grupo 4.
Luego de validar con el regex, comprobamos que el dígito verificador esperado para los primeros 11 o 12 caracteres coincida con el dígito verificador ingresado (el último caracter). Se utiliza una adaptación del método para códigos de control llamado Módulo 11 o ISBN 10.
Ya tenemos capturas por separado del texto de las 4 partes del RFC, en donde rfcSinDigito serán los primeros 11 o 12 caracteres y digitoVerificador será el último caracter.
//Separar el dígito verificador del resto del RFC const digitoVerificador = validado.pop(), rfcSinDigito = validado.slice(1).join(''),Pero si son 11 caracteres (RFC de persona moral -empresa), se lo ajusta para poder usar el mismo algoritmo para ambos. Se lo puede preceder con un espacio, o directamente ingresar el valor calculado.
if (len == 12) suma = 0 else suma = 481; //Ajuste para persona moralPara calcular el dígito esperado, primero se suma el índice de cada caracter desde 13 hasta 2, multiplicado por el valor de cada uno de los 12 caracteres, los cuales tienen un valor de 0 a 38 según este orden (diccionario):
0123456789ABCDEFGHIJKLMN&OPQRSTUVWXYZ Ñ for(var i=0; i<len; i++) suma = suma + diccionario.indexOf(rfcSinDigito.charAt(i)) * (indice - i);Y sobre la suma, se toma el complemento a 11 del resto de dividir por 11 (o módulo 11, de ahí el nombre del método).
digitoEsperado = 11 - suma % 11;Si da 11, se convierte en 0. Si da 10, se convierte en A.
if (digitoEsperado == 11) digitoEsperado = 0; else if (digitoEsperado == 10) digitoEsperado = "A";Ahora sí, podemos comparar si coinciden para devolver el resultado.
if (digitoVerificador != digitoEsperado) return false;Pero agregamos 2 excepciones, para los casos especiales de RFCs genéricos (Preguntas y respuestas sobre Comprobación Fiscal, puntos 5 y 6 📄), que no son RFCs válidos de personas físicas o morales, pero se utilizan para: 1. XAXX010101000 ::: Operaciones efectuadas con público en general. 2. XEXX010101000 ::: Operaciones efectuadas con residentes en el extranjero que no se encuentren inscritos en el RFC.
if ((digitoVerificador != digitoEsperado) && (!aceptarGenerico || rfcSinDigito + digitoVerificador != "XAXX010101000")) return false; else if (!aceptarGenerico && rfcSinDigito + digitoVerificador == "XEXX010101000") return false;* Como se ve, estoy usando un segundo parámetro opcional (aceptarGenerico), en caso de que no se permitan.
Finalmente, si pasó todas las reglas anteriores, se devuelve el RFC limpio.
return rfcSinDigito + digitoVerificador;Từ khóa » Hay Rfc Con ñ
-
Letra Ñ En El RFC - ValidaCFD
-
¿Cómo Formar El RFC?
-
[PDF] Especificaciones Técnicas - SAT
-
[PDF] Especificaciones Técnicas - SAT
-
Patrones Reportan Problemas Por El Uso De La "Ñ" En RFC E IMSS
-
[PDF] REGLAS PARA FORMAR RFC - Realce Valor
-
Registro Federal De Contribuyentes - Wikipedia, La Enciclopedia Libre
-
Calculo Del RFC Para Personas Fisicas - Solución Factible
-
Validar RFC, Nombre O Razón Social Y Código Postal En El SAT
-
Validación De RFC De Clientes - Proscai
-
Solución Al Error “Nombre O Razón Social Incorrecto” En CFDI 4.0
-
Errores Al Facturar El CFDI 4.0 Por Datos Del Receptor - ContadorMx
-
Generar Archivo Con RFC, Nombre Y CP - NET