Saltar al contenido

Validación del módulo 11 (RUT y Patente en Chile)

by en 20 agosto, 2013

Hace bastante tiempo que no escribo una entrada en el blog, llegó la hora de revivirlo 🙂

El módulo 11 es un código de control usado para la validación de un dato al añadir un dígito verificador, en chile es usado para validar el RUN (Rol Único Nacional), RUT (Rol Único  Tributario) y la Patente de los vehículos (no sé si se utilizará para otras cosas).

Esta entrada está enfocada en la validación del módulo 11 y la aplicación en C# para validar un RUN/RUT y una Patente chilena.

El módulo 11: El método denominado módulo 11 detecta errores en un solo dígito e intercambios simples o dobles. Se basa en aplicar un factor de chequeo ponderado a cada dígito del número original.

El Registro Civil (chile) ofrece manuales para validar correctamente el RUT/RUN y la patente.

Para validar el módulo 11 tenemos el siguiente código (gentileza de Germán Aroca):

public class Mod11Validator
{
    public int Numero { get; set; }
    public string DigitoVerificador { get; set; }

    public Mod11Validator(int numero, string digitoVerificador)
    {
        this.Numero = numero;
        this.DigitoVerificador = digitoVerificador.ToUpper();
    }

    public bool ObtenerValidezMod11()
    {
        return this.DigitoVerificador == CalcularDigitoVerificador(this.Numero);
    }

    private string CalcularDigitoVerificador(int numero)
    {
        string cadenaNumero = numero.ToString();
        int calculador = 0;

        int[] factores = {3, 2, 7, 6, 5, 4, 3, 2};
        int indiceFactor = factores.Length - 1;

        for (int i = cadenaNumero.Length - 1; i >= 0; i--)
        {
            calculador = calculador + (factores[indiceFactor]*int.Parse(cadenaNumero.Substring(i, 1)));
            indiceFactor--;
        }

        string digitoVerificador;
        int resultado = 11 - (calculador%11);

        if (resultado == 11)
        {
            digitoVerificador = "0";
        }
        else if (resultado == 10)
        {
            digitoVerificador = "K";
        }
        else
        {
            digitoVerificador = resultado.ToString();
        }

        return digitoVerificador;
    }
}

Para validar el RUT/RUN por lo tanto solo debemos llamar a este método de la siguiente forma

Mod11Validator mod11 = new Mod11Validator(numero, dv);
bool esValido = mod11.ObtenerValidezMod11();

Para la validación de patente es un tema distinto, dado que la validación de la patente lleva letras, estas deben ser convertidas en dígitos de acuerdo al manual del registro civil. Entiendo que traspasar todas estas letras a dígitos es realmente aburrido y tedioso, les dejo adjunto 2 archivos CSV con las conversiones de patentes nuevas y antiguas Cortesía de Carlos Muñoz.

Para utilizar estos archivos correctamente con la clase que embedo a continuación, solo deben añadir los archivos a un archivo de recursos y luego mapearlos (ver líneas destacadas en el código). Por cierto, para leer los archivos utilizo el siguiente código:  Leer CSV (archivo separado por coma)

public class PatenteValidator
{
    public class PatenteAntigua
    {
        public static Dictionary<string, string> ValorLetras
        {
            get
            {
                DataTable dt =
                    Utils.Common.Files.FileTools.ByteBufferToTable(ValidatorResources.Resources.DiccionarioPatentesAntiguas, true);
                Dictionary<string, string> d = new Dictionary<string, string>();
                foreach (DataRow dr in dt.Rows)
                    d[dr[0].ToString()] = dr[1].ToString();

                return d;
            }
        }
    }

    public class PatenteNueva
    {
        public static Dictionary<string, string> ValorLetras
        {
            get
            {
                DataTable dt =
                    Utils.Common.Files.FileTools.ByteBufferToTable(ValidatorResources.Resources.DiccionarioPatentesNuevas, true);
                Dictionary<string, string> d = new Dictionary<string, string>();
                foreach (DataRow dr in dt.Rows)
                    d[dr[0].ToString()] = dr[1].ToString();

                return d;
            }
        }
    }

    public static bool ValidarPatente(string patente)
    {
        if (patente.Trim().Length != 8)
            return false;
        if (!patente.Trim().Contains("-"))
            return false;

        int aux;
        bool esPatenteAntigua = int.TryParse(patente.Substring(2,2), out aux);
        int numero;
        string dv;
        if(esPatenteAntigua)
        {
            Dictionary<string, string> valorLetras = PatenteAntigua.ValorLetras;
            string letras = patente.Substring(0, 2);
            if (!valorLetras.ContainsKey(letras.ToUpper()))
                return false;
            string valor = valorLetras[letras.ToUpper()];
            valor += patente.Substring(2, 4);
            dv = patente.Substring(7, 1);
            numero = int.Parse(valor);
        }
        else
        {
            Dictionary<string, string> valorLetras = PatenteNueva.ValorLetras;
            char[] letras = patente.Substring(0, 4).ToCharArray();
            string valor = string.Empty;

            foreach (char c in letras)
            {
                if (!valorLetras.ContainsKey(c.ToString().ToUpper()))
                    return false;
                valor += valorLetras[c.ToString().ToUpper()];
            }

            valor += patente.Substring(4, 2);
            dv = patente.Substring(7, 1);
            numero = int.Parse(valor);
        }

        Mod11Validator mod11Validator = new Mod11Validator(numero, dv);
        return mod11Validator.ObtenerValidezMod11();
    }
}

From → C#

21 comentarios
  1. Felipe permalink

    El validado de patente no funciona

    • Podrías ser un poco más específico en el error? Yo lo tengo implementado y funciona.

      • Felipe permalink

        El dígito verificador que devuelve no corresponde con el ultimo dígito de la patente en todas las patentes que e ingresado.

  2. ¿estás seguro? yo lo tengo implementado y funciona perfecto, considera que recibe patentes AA0000-1 y AAAA00-1. Lo que calcula es el digito verificador según lo establecido por el registro civil.

  3. sergio permalink

    no entiendo la function de leer el cvs. la function recibe buffer As Byte() pero los cvs son string…..

    • Entiendo perfectamente lo que dices, ten en cuenta que toda representación de datos es un arreglo de bytes, en el caso de un CSV, ese arreglo de Bytes es texto simple, por lo cual no es necesario interpretar el arreglo como string, sino que lo es por defecto.

      Si lo que deseas es una función «StringToDataTable» que interprete un string en formato CSV, yo utilizo la siguiente: https://gist.github.com/Gabriel-Espinoza/1c86fec6e757fad3834e
      Avísame si te sirve 🙂

      • sergio permalink

        algo estoy haciendo mal entonces. yo agrego los archivos «csv» al resource pero luego al invocarlos me lanza un error: Dim dt As DataTable = ByteBufferToTable(My.Resources.DiccionarioPatentesAntiguas, True)

        Un valor de tipo ‘String’ no se puede convertir en ‘1-matriz dimensional de Byte’.

      • No había reparado en que estás usando VB.NET, de ser así, te recomiendo utilizar la función que te dejé linqueada en la respuesta anterior, ahí interpretas el CSV y lo lees. Prueba y me cuentas como te fue.

        Saludos

  4. sergio permalink

    Gracias! ocupé las clases que tienes en GitHub… exelente!

  5. luis permalink

    validar patente pero en vba. tu serias tan amable de colocarlo

  6. Erik permalink

    Podrias enviar tu codigo a este sitio que tiene muchas funciones.

    El de rut y patente

    http://users.dcc.uchile.cl/~mortega/microcodigos/validarrut/

  7. Marcelo permalink

    estimado me podrías mandar el código de la validación de Rut a este correo marcelo.mora.jara@gmail.com gracias

  8. Daniel permalink

    Como ocupo Utils?, me dice que no existe y no se como implementarla en mi codigo. Agregue Utils a referencias pero no me lo reconoce

  9. Muy bien explicado, pero los enlaces a los csv, están rotos :/ .

Replica a Gabriel Espinoza Erices Cancelar la respuesta