Comparto con vosotros esta macro que realiza una validación del campo DNI de una tabla. Admite como parámetros el nombre de la tabla (DNIS) y el nombre del campo con el DNI (DNI). Como salida genera otra tabla que se llama DNIS_ (añade un subrallado al final) y le añade el campo dni_norm. La macro normaliza DNIs y NIEs españoles.
En el primer paso se verifica el formato del DNI y se rechazan los que tengan un formato que no sea compatible. Estos se marcan con el indicador ind_valido. Para aquellos que cumplen con el formato básico de los DNIs, trocea ese DNI en prefix, number y sufix, De forma que se validan por separado.
En el segundo paso se normaliza la parte numérica del DNI dándole tantos dígitos como vaya a necesitar añadiendo ceros por la izquierda. En el tercer paso se calcula la letra del DNI/NIE y se juntan todos los trozos para tener el DNI normalizado. En un último paso se realiza el cruce que la tabla inicial de DNIs.
%macro normalizar_dni(tabla=,campo=);
/* obtenemos las partes del DNI y localizamos formatos incorrectos */
data norm1;
set &tabla;
&campo = upcase(&campo);
if anypunct(&campo) > 0 then ind_valido = 0;
else if length(&campo) > 9 then ind_valido = 0;
else if 0 < anyalpha(substr(&campo,2)) < length(substr(&campo,2)) then ind_valido = 0;
else if compress(substr(&campo,1,1),'XYZ','D') ne '' then ind_valido = 0;
else if length(&campo)=9 and anyalpha(&campo)=0 and substr(&campo,1,1)='0' then do;
&campo=substr(&campo,2);
ind_valido = 1;
prefix = compress(substr(&campo,1,1),'','D');
number = input(compress(&campo,'','A'),8.);
sufix = compress(substr(&campo,length(&campo)),'','D');
end;
else if length(&campo)=9 and anyalpha(&campo)=0 then ind_valido = 0;
else do;
ind_valido = 1;
prefix = compress(substr(&campo,1,1),'','D');
number = input(compress(&campo,'','A'),8.);
sufix = compress(substr(&campo,length(&campo)),'','D');
end;
run;
/* normalizamos el número */
data norm2;
set norm1;
format numero $8.;
length numero $ 8;
n = number;
if anyalpha(prefix)=1 then numero = put(number,z7.);
else numero = put(number,z8.);
run;
/* calculamos la letra del DNI y verificamos si es correcta cuando venga informada */
data norm3 (drop=prefix number sufix numero n letras resto letra_norm ind_valido);
set norm2;
letras = 'TRWAGMYFPDXBNJZSQVHLCKE';
if prefix='Y' then n=n+10000000;
if prefix='Z' then n=n+20000000;
resto = mod(n,23);
letra_norm = substr(letras,resto+1,1);
dni_norm = compress(prefix||numero||letra_norm);
run;
/* salida */
proc sql;
create table &tabla._ as
select a.*, dni_norm
from &tabla a
left join norm3 b
on a.&campo = b.&campo;
quit;
%mend normalizar_dni;
Podéis probarla con este set de datos de prueba que os dejo aquí:
data DNIS;
format dni $20.;
length dni $ 20;
input dni $;
datalines;
16634732A
1b
16634732
32631459w
X00123
Y1234612
123&134
Z1224536
X00z12
064563314
6843131058
1635740.65
000000315
G12
run;
%normalizar_dni(tabla=DNIS,campo=dni);