A raíz el artículo en el que explicaba como leer un fichero de texto desde excel, un lector del blog, me preguntó como podía automatizar la tarea de leer solo una parte en concreto, de un fichero de texto. Como su pregunta no me quedaba clara, le dije que me mandara el fichero y que me dijera qué es lo que quería leer concretamente, y vería si era capaz de resolver su duda.
Cuando abrí el fichero, y leí lo que quería hacer, vi rápidamente la utilidad de escribir este artículo. Y en eso estamos. Para que entendáis la idea, imaginad un fichero de texto plano, generado por un software cualquiera, que tiene X líneas, pero de las cuales, nos interesa obtener solo unas cuantas, y además, de esas cuantas líneas, solo nos interesa una parte del texto comprendido en ellas. ¿Un poco lioso, verdad?. Bueno, vamos a verlo con el mismo ejemplo que me pasó el amigo Victor Fajardo, pues me ha autorizado a hacerlo público.
Imaginad que tenemos un fichero de texto como este (pantallazo de un fragmento del fichero), que contiene información topográfica:

Ahora la cuestión radica en poder obtener una serie de datos que hay en el fichero de texto. En concreto aquellos valores que indican el punto geodésico, la latitud sur, la longitud oeste, la altura elipsoidal, la coordenada norte, la coordenada este, la altura ortométrica, y el factor de escala de proyección.
Quizás te preguntes ¿y dónde está todo eso?. Pues esa misma pregunta me la hice yo, pero el amigo Fajardo, ya me la resolvía antes de planteársela. Me dijo que esos datos figuraban en el fichero de texto, y eran los que aparecían coloreados en la siguiente imagen:

Perfecto, ya iba entendiendo lo que quería hacer. Quería obtener una serie de datos que se repetían cada X líneas, para pasarlos a un fichero de excel, sin tener que hace un copiar y pegar, o sin tener que escribirlos a mano, mientras los leía en el fichero de texto. Vamos, que quería obtener una tabla de excel como esta:

Fantástico. Ya tenemos todos los datos necesarios para empezar a plantear el problema. Tenemos el fichero de texto, sabemos qué datos queremos obtener, y sabemos como queremos presentarlos. Lo único que nos queda es resolver el problema.
Cuando se nos presenta un problema de este tipo, lo primero que tenemos que hacer es pensar si el fichero de texto sigue un patrón de comportamiento común. Si lo tiene, nuestro problema se resuelve de una forma más sencilla.
Veamos si existe ese patrón de comportamiento. Lo primero que observamos, es que el fichero de texto tiene una cabecera donde nos aparece lo que puede ser el software que lo ha generado (haced doble clic en la primera imagen que aparece en este artículo, para poder ampliar la imagen del fichero de texto), y algunas líneas más de carácter general. Luego, un poco más abajo, vemos que hay una serie de bloques de texto, que contienen datos homogéneos. En concreto hay 8 líneas de texto, luego 1 línea en blanco, luego otras 8 líneas de texto, y así sucesivamente, hasta llegar al final del fichero.
Para poder obtener los datos relativos al punto geodésico, a la latitud sur, a la longitud oeste, a la altura elipsoidal, a la coordenada norte, a la coordenada este, a la altura ortométrica, y el factor de escala de proyección, podemos utilizar varias técnicas. Por ejemplo, para obtener la Longitud Oeste (el dato que hay detrás del texto "Lon: W"), a bote pronto, se me ocurre que lo más sencillo va a ser hacer lo siguiente, pues existe un patrón de comportamiento idéntico en los datos del fichero:
1.- Buscaremos en todas las líneas, aquellas que contengan el texto "Lon: W".
2.- Una vez hayamos encontrado ese texto, nos quedaremos con los siguientes 21 caracteres, pues a partir de ese carácter ya obtenemos otro dato diferente a la longitud oeste.
3.- Como además el amigo Victor Fajardo quería añadir los grados, minutos y segundos, deberemos descomponer esos 21 caracteres, en tres grupos. Caca uno de ellos estará separado por un espacio vacío, y contendrá un bloque de números. El primer grupo serán los que representaremos con grados, el segundo con los minutos, y el tercero con los segundos.
Pues bien, eso nos sirve para obtener el dato correspondiente a la longitud oeste, pero ¿y el resto de los datos?. Pues exactamente igual. Para el resto de datos que queramos importar, haremos exactamente lo mismo, pero seleccionando aquellos caracteres que nos definan las variables a importar. En lugar de "Lon: W", serán " hgt:", "n:", etc.
Para el caso concreto del primer dato que queremos obtener, es decir, el punto geodésico, como no hay ningún texto a partir del cual sepamos que lo que hay detrás es lo que nos sirve, yo he optado por hacer lo siguiente:
1.- Hemos buscado la palabra "(meters)", que está en la 2ª línea de esos bloques de los que hablábamos antes, y que estaban formados por 8 líneas de texto.
2.- Hemos retrocedido una línea, para pasar a la línea 1 (recordemos que "(meters)" está en la segunda línea).
3.- Nos hemos quedado con los 19 primeros caracteres de esa primera línea.
Como veis, solo es cuestión de buscar el patrón de comportamiento del fichero de texto, para a partir de él, obtener cada uno de los datos que necesitamos.
Y no hay más secreto... Bueno sí. Para ahorrarnos dolores de cabeza, lo primero que hemos hecho, ha sido importar todo el fichero de texto, en una zona de la hoja de cálculo que no nos moleste, y luego a partir de esos datos, es con los que hemos trabajado (el fichero de texto, una vez importado todo él, lo cerramos). Una vez tengamos todo listo, y bien bonito en nuestra hoja de cálculo, borraremos todos esos datos que nos han servido de borrador (todos los datos importados a lo bruto y que hemos escrito en una zona de la hoja de cálculo en la que no estorbe).
El código que nos permite importar todos esos datos, será este:
Sub leer_fichero_de_texto() On Error Resume Next 'Ocultamos el procedimiento Application.ScreenUpdating = False 'eliminamos todo lo que haya escrito desde A6 hasta abajo Range("A6").Select Range(Selection, Selection.End(xlDown)).Select Selection.EntireRow.Delete 'informamos del nombre del fichero de texto fichero_de_texto = "datos.txt" 'Creamos el objeto FileSystemObject Set fso = CreateObject("Scripting.FileSystemObject") 'Abrimos el fichero. Si el fichero de texto no está 'en la misma ruta que el fichero de excel donde tenemos 'este macro, deberemos poner la ruta de esta forma: 'Set archivo = fso.OpenTextFile("E:\excel\" & fichero_de_texto, 1) 'Como supondremos que tenemos el fichero de texto 'en la misma ruta, pondremos esto otro: ruta = ActiveWorkbook.Path Set archivo = fso.OpenTextFile(ruta & "\" & fichero_de_texto, 1) 'Cargamos en una variable todas las líneas contenido = archivo.readall 'Cerramos el fichero archivo.Close 'Limpiamos los objetos Set fso = Nothing Set archivo = Nothing 'creamos un array con los datos, 'y los separamos por los intros que haya 'en el fichero de texto (cada "intro" es 'una línea nueva). Tecla intro = vbCrLf contenido = Split(contenido, vbCrLf) 'empezamos a escribir en la celda I6 Range("I6").Select 'Para todos los elementos del vector... For i = 0 To UBound(contenido) 'Vamos escribiendo línea a línea ActiveCell = contenido(i) 'Pasamos a la siguiente línea ActiveCell.Offset(1, 0).Select Next 'seguimos con el bucle 'fichamos la celda hasta la que hemos llegado 'para extraer la fila deonde estamos fila_final = ActiveCell.Row 'Nos situamos en la columna I, a partir de I6 Range("I6").Select 'Ahora vamos a coger los datos que nos interesan, 'para todo el rango de filas que van desde la 'fila 1, hasta la fila_final For i = 1 To fila_final 'fichamos la celda donde estamos, para volver a ella celda = ActiveCell.Address '****************************************** ' PUNTO GEODÉSICO '****************************************** 'si la fila contiene la palabra " (meters) ", fichamos la fila de arriba 'que es la que contiene el punto geodésico If InStr(LCase(ActiveCell), " (meters) ") > 1 Then 'cogemos los 19 primeros caracteres, pues a partir 'del 20, ya aparece la fecha y la hora punto_geodesico = Left(ActiveCell.Offset(-1, 0), 19) 'Escribimos los datos a partir de A6 Range("A6").Select 'Escribimos el título ActiveCell = "PUNTO GEODÉSICO" 'lo ponemos en negrita, subrayado, y en rojo With Selection .Font.Bold = True .Font.Underline = xlUnderlineStyleSingle .Font.ColorIndex = 3 End With 'buscamos la primera celda vacía Do While Not IsEmpty(ActiveCell) ActiveCell.Offset(1, 0).Select Loop 'y escribimos el dato x ActiveCell = punto_geodesico End If 'volvemos donde estábamos Range(celda).Select '****************************************** ' LATITUD SUR '****************************************** 'si la fila contiene la palabra " Lat: S ", fichamos la fila 'que contiene la latitud sur If InStr(LCase(ActiveCell), " lat: s ") > 1 Then 'cogemos desde el caracter 35, hasta el 56, 'es decir, 21 caracteres más, a partir del 35, 'con "trim" quitaremos los espacios vacíos de delante y detrás lati_sur = Trim(Mid(ActiveCell, 35, 21)) 'descomponemos el valor en los tres elementos, 'con el delimitador de espacio " " latitud_sur = Split(lati_sur, " ") 'añadimos los grados, minutos y segundos, a cada elemento (el 0, el 1, y el 2) 'pues los elemenos del vector, empiezan por 0 latitud_sur = latitud_sur(0) & "º" & latitud_sur(1) & "'" & latitud_sur(2) & """" 'Escribimos los datos a partir de B6 Range("B6").Select 'Escribimos el título ActiveCell = "LATITUD SUR" 'lo ponemos en negrita, subrayado, y en rojo With Selection .Font.Bold = True .Font.Underline = xlUnderlineStyleSingle .Font.ColorIndex = 3 End With 'buscamos la primera celda vacía Do While Not IsEmpty(ActiveCell) ActiveCell.Offset(1, 0).Select Loop 'y escribimos el dato x ActiveCell = latitud_sur End If 'volvemos donde estábamos Range(celda).Select '****************************************** ' LONGITUD OESTE '****************************************** 'si la fila contiene la palabra " Lon: W ", fichamos la fila 'que contiene la longitud oeste If InStr(LCase(ActiveCell), " lon: w ") > 1 Then 'cogemos desde el caracter 35, hasta el 56, 'es decir, 21 caracteres más, a partir del 35, 'con "trim" quitaremos los espacios vacíos de delante y detrás long_oeste = Trim(Mid(ActiveCell, 35, 21)) 'descomponemos el valor en los tres elementos, 'con el delimitador de espacio " " longitud_oeste = Split(long_oeste, " ") 'añadimos los grados, minutos y segundos, a cada elemento (el 0, el 1, y el 2) 'pues los elemenos del vector, empiezan por 0 longitud_oeste = longitud_oeste(0) & "º" & longitud_oeste(1) & "'" & longitud_oeste(2) & """" 'Escribimos los datos a partir de C6 Range("C6").Select 'Escribimos el título ActiveCell = "LONGITUD OESTE" 'lo ponemos en negrita, subrayado, y en rojo With Selection .Font.Bold = True .Font.Underline = xlUnderlineStyleSingle .Font.ColorIndex = 3 End With 'buscamos la primera celda vacía Do While Not IsEmpty(ActiveCell) ActiveCell.Offset(1, 0).Select Loop 'y escribimos el dato x ActiveCell = longitud_oeste End If 'volvemos donde estábamos Range(celda).Select '****************************************** ' ALTURA ELIPSOIDAL '****************************************** 'si la fila contiene la palabra " Hgt: ", fichamos la fila 'que contiene la altura elipsoidal If InStr(LCase(ActiveCell), " hgt: ") > 1 Then 'cogemos desde el caracter 35, hasta el 56, 'es decir, 21 caracteres más, a partir del 35, 'con "trim" quitaremos los espacios vacíos de delante y detrás altura_elipsoidal = Trim(Mid(ActiveCell, 35, 21)) 'Escribimos los datos a partir de D6 Range("D6").Select 'Escribimos el título ActiveCell = "ALTURA ELIPS." 'lo ponemos en negrita, subrayado, y en rojo With Selection .Font.Bold = True .Font.Underline = xlUnderlineStyleSingle .Font.ColorIndex = 3 End With 'buscamos la primera celda vacía Do While Not IsEmpty(ActiveCell) ActiveCell.Offset(1, 0).Select Loop 'y escribimos el dato x ActiveCell = altura_elipsoidal End If 'volvemos donde estábamos Range(celda).Select '****************************************** ' COORDENADA NORTE '****************************************** 'si la fila contiene la palabra " N: ", fichamos la fila 'que contiene la coordenada norte If InStr(LCase(ActiveCell), " n: ") > 1 Then 'cogemos desde el caracter 58, hasta el 71, 'es decir, 13 caracteres más, a partir del 58, 'con "trim" quitaremos los espacios vacíos de delante y detrás coordenada_norte = Trim(Mid(ActiveCell, 58, 13)) 'Escribimos los datos a partir de E6 Range("E6").Select 'Escribimos el título ActiveCell = "COORD. NORTE" 'lo ponemos en negrita, subrayado, y en rojo With Selection .Font.Bold = True .Font.Underline = xlUnderlineStyleSingle .Font.ColorIndex = 3 End With 'buscamos la primera celda vacía Do While Not IsEmpty(ActiveCell) ActiveCell.Offset(1, 0).Select Loop 'y escribimos el dato x ActiveCell = coordenada_norte End If 'volvemos donde estábamos Range(celda).Select '****************************************** ' COORDENADA ESTE '****************************************** 'si la fila contiene la palabra " E: ", fichamos la fila 'que contiene la coordenada este If InStr(LCase(ActiveCell), " e: ") > 1 Then 'cogemos desde el caracter 58, hasta el 71, 'es decir, 13 caracteres más, a partir del 58, 'con "trim" quitaremos los espacios vacíos de delante y detrás coordenada_este = Trim(Mid(ActiveCell, 58, 13)) 'Escribimos los datos a partir de F6 Range("F6").Select 'Escribimos el título ActiveCell = "COORD. ESTE" 'lo ponemos en negrita, subrayado, y en rojo With Selection .Font.Bold = True .Font.Underline = xlUnderlineStyleSingle .Font.ColorIndex = 3 End With 'buscamos la primera celda vacía Do While Not IsEmpty(ActiveCell) ActiveCell.Offset(1, 0).Select Loop 'y escribimos el dato x ActiveCell = coordenada_este End If 'volvemos donde estábamos Range(celda).Select '****************************************** ' ALTURA ORTOMÉTRICA '****************************************** 'si la fila contiene la palabra " Orth: ", fichamos la fila 'que contiene la altura ortométrica If InStr(LCase(ActiveCell), " orth: ") > 1 Then 'cogemos desde el caracter 61, hasta el 71, 'es decir, 10 caracteres más, a partir del 61, 'con "trim" quitaremos los espacios vacíos de delante y detrás altura_ortometrica = Trim(Mid(ActiveCell, 61, 10)) 'Escribimos los datos a partir de G6 Range("G6").Select 'Escribimos el título ActiveCell = "ALTURA ORTO." 'lo ponemos en negrita, subrayado, y en rojo With Selection .Font.Bold = True .Font.Underline = xlUnderlineStyleSingle .Font.ColorIndex = 3 End With 'buscamos la primera celda vacía Do While Not IsEmpty(ActiveCell) ActiveCell.Offset(1, 0).Select Loop 'y escribimos el dato x ActiveCell = altura_ortometrica End If 'volvemos donde estábamos Range(celda).Select '****************************************** ' FACTOR DE ESCALA DE PROYECCIÓN '****************************************** 'si la fila contiene la palabra " Grid Scale: ", fichamos la fila 'que contiene el factor de escala de proyección If InStr(LCase(ActiveCell), " grid scale: ") > 1 Then 'cogemos desde el caracter 67, hasta el 79, 'es decir, 12 caracteres más, a partir del 79, 'con "trim" quitaremos los espacios 'vacíos de delante y detrás factor_escala = Trim(Mid(ActiveCell, 67, 12)) 'Escribimos los datos a partir de H6 Range("H6").Select 'Escribimos el título ActiveCell = "FACTOR ESCALA PROY." 'lo ponemos en negrita, subrayado, y en rojo With Selection .Font.Bold = True .Font.Underline = xlUnderlineStyleSingle .Font.ColorIndex = 3 End With 'buscamos la primera celda vacía Do While Not IsEmpty(ActiveCell) ActiveCell.Offset(1, 0).Select Loop 'y escribimos el dato x ActiveCell = factor_escala End If 'volvemos donde estábamos Range(celda).Select '****************************************** 'ahora bajamos una fila ActiveCell.Offset(1, 0).Select Next 'continuamos con el bucle 'finalmente eliminamos los datos que 'habíamos escrito en la columna I Columns("I:I").Select Selection.Delete Shift:=xlToLeft 'nos situamos en A6 Range("A6").Select 'Mostramos el procedimiento Application.ScreenUpdating = True End Sub
|
Quizás ese código puede que os parezca un poco largo, pero en realidad, como estamos usando la misma técnica para importar la latitud sur, la longitud oeste, la altura elipsoidal, etc., pues nos bastará con copiar y pegar determinadas partes del código, para retocarla posteriormente.
Una vez ejecutemos ese macro (con el fichero de texto llamado "datos.txt", y en la misma carpeta que el fichero de excel), obtendremos esto:

Con este macro, lo que conseguimos es que cada vez que tengamos que trabajar con el fichero de tiempo, no perdamos horas (da igual lo largo que sea el fichero de texto), haciendo un copiar y pegar, o bien transcribiendo a mano los datos del fichero de texto, directamente en excel. Ahora con tan solo pulsar un botón en la hoja de cálculo, obtendremos los datos deseados del fichero de texto.
Si deseáis ver esto con vuestros propios ojos, desde aquí podéis
descargar un fichero comprimido que contiene tanto la hoja de cálculo, como el fichero de texto que he utilizado en este artículo.