Publicado el :
ETL CREATION_INTERNE

Lectura y corrección de datos delimitados con delimitadores faltantes

Este código también está disponible en: Deutsch English Français
En espera de validación
El objetivo principal de este script es proporcionar estrategias para un problema común al importar archivos planos: los delimitadores faltantes. El script primero crea un archivo de texto temporal ('C:\TEMP\osbbb.txt') que contiene intencionalmente líneas con delimitadores faltantes. Luego, intenta leer este archivo con una instrucción INFILE estándar, demostrando los errores resultantes (desplazamiento de columnas). Finalmente, propone dos enfoques correctivos dentro de un paso DATA: el primero utilizando las funciones SAS© FIND y SUBSTR con la variable automática _INFILE_, y el segundo, más conciso, aprovechando la función PRXCHANGE con una expresión regular para insertar los delimitadores faltantes antes de la lectura final.
Análisis de datos

Type : CREATION_INTERNE


Los datos se generan directamente en el script a través de un paso DATA _NULL_, que escribe un archivo de texto delimitado con delimitadores faltantes intencionales. Este archivo temporal se utiliza posteriormente como fuente para los pasos DATA de lectura y corrección.

1 Bloque de código
DATA STEP Data
Explicación :
Este bloque inicializa una referencia de archivo (FILENAME) a un archivo de texto llamado 'osbbb.txt' en 'C:\TEMP'. Luego, se utiliza un paso DATA _NULL_ para crear y escribir líneas de datos en este archivo. El contenido incluye una línea de encabezado y varias líneas de datos, algunas de las cuales tienen delimitadores faltantes intencionalmente (por ejemplo, 'Gannet~22JUL2018~Y' le falta el segundo delimitador entre 'Gannet' y '22JUL2018'), simulando así un escenario de datos corruptos para las pruebas posteriores.
¡Copiado!
1FILENAME MISSING 'C:\TEMP\osbbb.txt';
2 
3DATA _NULL_;
4 file MISSING;
5 put 'Animal~Mode~Date~Bird';
6 put 'Beaver~~09OCT2019~N';
7 put 'Gannet~22JUL2018~Y';
8 * ^-- missing delimiter;
9 put 'Peacock~~17DEC2017~Y';
10 put 'Robin~23FEB2019~Y';
11 * ^-- missing delimiter;
12 put 'Nuthatch~19APR2019~Y';
13 * ^-- missing delimiter;
14RUN;
2 Bloque de código
DATA STEP Data
Explicación :
Este paso DATA intenta leer el archivo 'MISSING' creado previamente. La instrucción INFILE utiliza el delimitador tilde (~), la opción DSD para tratar los delimitadores consecutivos como valores faltantes, FIRSTOBS=2 para ignorar el encabezado, y TRUNCOVER para evitar errores cuando las líneas son más cortas de lo esperado. Sin embargo, debido a los delimitadores faltantes que no son delimitadores consecutivos sino desplazamientos, este bloque demuestra que la lectura fallará para los registros corruptos, lo que resultará en datos asignados o truncados incorrectamente.
¡Copiado!
1DATA missing;
2 INFILE MISSING dlm='~' DSD firstobs=2 truncover;
3 FORMAT Animal $8. Mode $5. Date DATE9. Bird $1.;
4 INPUT Animal Mode Date:DATE9. Bird;
5RUN;
3 Bloque de código
DATA STEP Data
Explicación :
Este paso DATA propone una primera solución para corregir los delimitadores faltantes. La instrucción 'input @;' lee la línea completa en la variable automática _INFILE_ sin analizarla. Luego usa la función SCAN para verificar el contenido supuesto de la cuarta columna ('field4'). Si 'field4' no es 'Y' o 'N', indica un delimitador faltante. En este caso, el código encuentra el primer delimitador (FIND) e inserta un tilde ('~') adicional después de él manipulando la cadena _INFILE_ con SUBSTR. Finalmente, una segunda instrucción INPUT vuelve a leer la línea corregida de _INFILE_ para un análisis correcto. Las variables temporales DLM1AT y field4 se eliminan posteriormente (DROP).
¡Copiado!
1DATA fixed (drop=DLM1AT field4);
2 INFILE MISSING dlm='~' DSD firstobs=2;
3 FORMAT Animal $8. Mode $5. Date DATE9. Bird $1.;
4 INPUT @;
5 LENGTH field4 $1;
6 field4 = scan(_INFILE_, 4, '~', 'M');
7 IF field4 not in ('Y', 'N') THEN DO;
8 DLM1AT = FIND(_INFILE_, '~');
9 _INFILE_ = SUBSTR(_INFILE_, 1, DLM1AT) ||
10 '~' || SUBSTR(_INFILE_, DLM1AT + 1);
11 END;
12 INPUT Animal Mode Date:DATE9. Bird;
13RUN;
4 Bloque de código
DATA STEP Data
Explicación :
Este paso DATA ofrece una solución más elegante y concisa utilizando expresiones regulares. Al igual que el bloque anterior, 'input @;' lee la línea completa en _INFILE_. Luego se utiliza la función PRXCHANGE para buscar un patrón específico: el inicio de la cadena, seguido de una secuencia de 1 a 8 caracteres que no sean tilde, luego un tilde, capturando todo en el primer grupo de captura (\1). Luego busca un carácter que no sea tilde inmediatamente después del primer grupo de captura (\2). Si se encuentra este patrón (lo que indica un delimitador faltante entre el primer y el segundo campo), inserta un tilde entre los dos grupos de captura (\1~\2), corrigiendo así _INFILE_. La línea corregida se lee luego mediante la instrucción INPUT final.
¡Copiado!
1DATA everythings_better_with_regex;
2 INFILE MISSING dlm='~' DSD firstobs=2;
3 FORMAT Animal $8. Mode $5. Date DATE9. Bird $1.;
4 INPUT @;
5 _INFILE_ = PRXCHANGE('s/^([^~]{1,8}~)([^~])/, 1, _INFILE_);
6 INPUT Animal Mode Date:DATE9. Bird;
7RUN;
Este material se proporciona "tal cual" por We Are Cas. No hay garantías, expresas o implícitas, en cuanto a la comerciabilidad o idoneidad para un propósito particular con respecto a los materiales o el código contenidos en este documento. We Are Cas no es responsable de los errores en este material tal como existe ahora o existirá, ni We Are Cas proporciona soporte técnico para el mismo.
Información de copyright : Paper 4839-2020 Read Before You Read: Reading, Rewriting & Re-Reading Difficult Delimited Data in a Data Step Appendix B - Complete Code for Missing Delimiters