Macro SAS: Validar DNI de Perú

Hoy voy a incluir una macro que sirve para validar con SAS un número de DNI peruano verificando si el dígito verificador es correcto o no.
Hay que empezar diciendo que inicialmente, y hasta 2007, los DNIs sin fecha de caducidad tenían un dígito verificador que correspondía con una de estas letras: A, B, C, D, E, F, G, H, I, J o K. En el resto de casos se asigna un número de 0 a 9 que sirve para verificar el resto de dígitos del DNI a través de una serie de operaciones matemáticas.
Para trabajar con algunos ejemplos alimentaremos la macro con la siguiente tabla con DNIs a evaluar:

/* Ejemplos*/;
data DNIS;
    format DNI $10.;
    input DNI;
    datalines;
    67415321-0
    1657351-A
    31874-1
    671354134
run;

La macro %validarDNI añade dos campos a la tabla que se le pase por parámetro: dni_normal y ind_valido. dni_normal es el valor del campo que contenía el DNI originalmente, pero normalizado. ind_valido toma dos valores posibles: 1 que indica que el DNI es correcto y 0 que indica que es erróneo.
%validarDNI acepta además dos parámetros obligatorios: el nombre de la tabla y el nombre del campo DNI a validar dentro de ella.

/*Macro*/;
%macro validarDNI(tabla=, campo=);
    data DNI1 (drop=a valor resto codigo:);
        set &tabla;
        rename &campo=dni_original;
        dni_normal = upcase(compress(&campo,'-_. '));
        a = 9 - length(dni_normal);
        if a > 0 then dni_normal = compress(repeat('0',a-1) || dni_normal);
        ind_valido = 1;
        if length(dni_normal) > 9 then ind_valido = 0;
        %do i = 1 %to 8;
            if 0 > put(substr(dni_normal,&i,1),8.) or put(substr(dni_normal,&i,1),8.) > 9 then ind_valido = 0;
        %end;
        if substr(dni_normal,9,1) not in ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K') then ind_valido = 0;
        if ind_valido > 0 then do;
            valor = 3*put(substr(dni_normal,1,1),8.) +
                    2*put(substr(dni_normal,2,1),8.) +
                    7*put(substr(dni_normal,3,1),8.) +
                    6*put(substr(dni_normal,4,1),8.) +
                    5*put(substr(dni_normal,5,1),8.) +
                    4*put(substr(dni_normal,6,1),8.) +
                    3*put(substr(dni_normal,7,1),8.) +
                    2*put(substr(dni_normal,8,1),8.);
            resto = mod(valor,11);
            if resto = 0 then resto = 11;
            resto = resto + 1;
            codigo1 = substr('67890112345',resto,1);
            codigo2 = substr('KABCDEFGHIJ',resto,1);
            if substr(dni_normal,9) ne codigo1 and substr(dni_normal,9) ne codigo2 then ind_valido = 0;
        end;
    run;

    data &tabla;
        set DNI1;
        rename dni_original = &campo;
    run;
%mend;
%validarDNI(tabla=DNIS, campo=DNI);

El algoritmo para calcular el dígito verificador del DNI es el siguiente: se multiplica cada número del DNI normalizado (sus 8 primeros dígitos) por el dígito que ocupe la misma posición en la cadena: 1, 7, 8, 0, 1, 1, 4, 6 y luego se suman todos los factores para dar una cifra de la que calcularemos el resto con resto a dividirla entre 11 (aquí, si el resto es 0 tomaremos 11).
Restamos 11 menos la resultante de la operación anterior. Le sumaremos 1 y entonces tomaremos ese valor para buscar el dígito correspondiente a esa posición en la cadena: 6, 7, 8, 9, 0, 1, 1, 2, 3, 4, 5. Este último es el dígito de verificación.