Is the calculation of RENAVAN correct? Can you improve something?

2

Hello, I'm searching the internet and found on this site a C # code for how to calculate RENAVAM, I moved a bit, but I can not find anywhere that explains how RENAVAM calculation really works so I do not know if this logic is correct.

Code in the .NET Fiddle

Code:

public static bool isRENAVAM(string RENAVAM)
        {
            if (string.IsNullOrEmpty(RENAVAM.Trim()))
                return false;

            int[] d = new int[11];
            //sequencia para calcular o RENAVAM
            string sequencia = "3298765432";
            string SoNumero = Regex.Replace(RENAVAM, "[^0-9]", string.Empty);

            if (string.IsNullOrEmpty(SoNumero))
                return false;

            //verificando se todos os numeros são iguais 
            if (new string(SoNumero[0], SoNumero.Length) == SoNumero) 
                return false;

            SoNumero = Convert.ToInt64(SoNumero).ToString("00000000000");

            int v = 0;
        for (int i = 0; i < 11; i++)
            d[i] = Convert.ToInt32(SoNumero.Substring(i, 1));

        for (int i = 0; i < 10; i++)
            v += d[i] * Convert.ToInt32(sequencia.Substring(i, 1));

        v = (v * 10) % 11;
        v = (v != 10) ? v : 0;

        return (v == d[10]);
    }

My questions are:

1. Is this code to calculate RENAVAM correct?

2. What is the rationale for calculating RENAVAM?

3. Is there anything I can improve on this code?

    
asked by anonymous 07.01.2016 / 17:09

2 answers

4

An improvement in the code:

    public static bool IsRENAVAM(string RENAVAM)
    {
        if (string.IsNullOrEmpty(RENAVAM.Trim()))
            return false;

        var sequencia = new int[]{ 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 };
        var soNumero = Regex.Replace(RENAVAM, "[^0-9]", string.Empty);

        if (string.IsNullOrEmpty(soNumero))
            return false;
        //verificando se todos os numeros são iguais 
        if (soNumero.Distinct().Count() ==1 )
            return false;

        var d = soNumero.ToCharArray().Select(i => int.Parse(i.ToString())).Take(11);
        var v = (d.Zip(sequencia, (n, seq) => n * seq).Sum() * 10) % 11;            
        v = (v != 10) ? v : 0;
        return (v == d.ElementAt(10));
    }
}

Using Zip Enumerable knocks a loop which decreases cyclomatic complexity and number of lines, converting the string soNumero to a IEnumerable<int> is much more performative than converting to long and to string again, a link to understand a little better because I used Zip in an enumerator rather than foreach in an array

    
07.01.2016 / 18:18
1

Follow the slightly improved code

public static bool isRENAVAM(string RENAVAM)
        {
            if (string.IsNullOrEmpty(RENAVAM.Trim()))
                return false;

            string SoNumero = Regex.Replace(RENAVAM, "[^0-9]", string.Empty);

            if (string.IsNullOrEmpty(SoNumero) || new string(SoNumero[0], SoNumero.Length) == SoNumero)
                return false;

            int[] d = new int[11];
            string sequencia = "3298765432";

            SoNumero = Convert.ToInt64(SoNumero).ToString("00000000000");

            int v = 0;
        for (int i = 0; i < 11; i++)
            d[i] = Convert.ToInt32(SoNumero.Substring(i, 1));

        for (int i = 0; i < 10; i++)
            v += d[i] * Convert.ToInt32(sequencia.Substring(i, 1));

        v = (v * 10) % 11;
        v = (v != 10) ? v : 0;

        return (v == d[10]);
    }
    
07.01.2016 / 17:43