Validação de CPF e CNPJ

C#
public static class ValidateDocument
{
    ///
    /// Validates CPF/CNPJ and reformats any missing left padding '0'
    ///
    public static bool FormatIfValidDocument(
        string document, 
        out string formattedAccount)
    {
        document = string.Join("", document
            .Where(c => c is >= '0' and <= '9')
            .Select(c => c));
        if (IsValidCpf(document) || IsValidCnpj(document))
        {
            formattedAccount = document;
            return true;
        }

        // Try CPF
        var cpfDoc = document.PadLeft(11, '0');
        if (IsValidCpf(cpfDoc))
        {
            formattedAccount = cpfDoc;
            return true;
        }

        // Try CNPJ
        var cnpjDoc = document.PadLeft(14, '0');
        if (IsValidCnpj(cnpjDoc))
        {
            formattedAccount = cnpjDoc;
            return true;
        }

        formattedAccount = "";
        return false;
    }

    private static readonly byte[] CpfMult1 = { 10, 9, 8, 7, 6, 5, 4, 3, 2 };
    private static readonly byte[] CpfMult2 = { 11, 10, 9, 8, 7, 6, 5, 4, 3, 2 };
    private static readonly byte[] CnpjMult1 = { 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 };
    private static readonly byte[] CnpjMult2 = { 6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 };

    private static bool IsValidCpf(string cpf) => IsValidNumber(cpf, CpfMult1, CpfMult2);

    private static bool IsValidCnpj(string cnpj) => IsValidNumber(cnpj, CnpjMult1, CnpjMult2);


    private static bool IsValidNumber(string doc, IReadOnlyCollection<byte> mult1, IReadOnlyCollection<byte> mult2)
    {
        byte GetModule11(IReadOnlyList<byte> data, IEnumerable<byte> mult)
        {
            var sum = mult.Select((t, i) => data[i] * t).Sum();
            var rest = sum % 11;
            return (byte)(rest < 2 ? 0 : (11 - rest));
        }

        var size = mult2.Count + 1;
        if (doc.Length != size || doc.All(c => c == doc[0]))
            // Test if length is OK and all numbers are not equal
            return false;
        var digits = doc.Select(d => (byte)(d - '0')).ToArray();

        var rest1 = GetModule11(digits, mult1);
        var updatedDigits = digits[..mult1.Count].Append(rest1).ToArray();
        var rest2 = GetModule11(updatedDigits, mult2);

        return doc.EndsWith($"{rest1}{rest2}");
    }
}

Last update: September 18, 2024
Created: September 18, 2024