function validar_cpf(cpf)
    if not cpf then return false end

    local apenas_digitos = cpf:gsub("%D", "")

    if #apenas_digitos ~= 11 then return false end

    if apenas_digitos:match("^([0-9])%1+$") then return false end

    local function calcular_digito(base, peso_inicial)
        local soma = 0
        for i = 1, #base do
            local digito = tonumber(base:sub(i, i))
            soma = soma + digito * (peso_inicial - i + 1)
        end
        local resto = (soma * 10) % 11
        if resto == 10 then resto = 0 end
        return resto
    end

    local base9 = apenas_digitos:sub(1, 9)
    local d1 = calcular_digito(base9, 10)
    if d1 ~= tonumber(apenas_digitos:sub(10, 10)) then return false end

    local base10 = base9 .. tostring(d1)
    local d2 = calcular_digito(base10, 11)
    if d2 ~= tonumber(apenas_digitos:sub(11, 11)) then return false end

    return true
end

function formatar_cpf(cpf)
    return cpf:gsub("(%d%d%d)(%d%d%d)(%d%d%d)(%d%d)", "%1.%2.%3-%4")
end


function validar_data_ISO8601(data)
    local ano, mes, dia = data:match("^(%d%d%d%d)%-(%d%d)%-(%d%d)$")
    if not ano then
        return false
    end

    ano = tonumber(ano)
    mes = tonumber(mes)
    dia = tonumber(dia)

    if mes < 1 or mes > 12 then
        return false
    end

    local diasPorMes = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}

    if (ano % 4 == 0 and ano % 100 ~= 0) or (ano % 400 == 0) then
        diasPorMes[2] = 29
    end

    if dia < 1 or dia > diasPorMes[mes] then
        return false
    end

    return true
end

function formatar_data(data)
    return string.format("%s/%s/%s", data:match("^(%d%d%d%d)%-(%d%d)%-(%d%d)$"))
end