En este link podrán tener acceso a la entrada que dió origien al planteamiento de Luis, quien necesita trabajar con dos archivos de texto, tomando cierta información de uno y volcándola a otro TXT, sin la necesidad de migrar esos registros a Excel. En varias ocasiones me tocó trabajar con archivos de texto con información tan heterogénea y mal distribuída, que necesité "depurar" el TXT de origen en uno nuevo, y luego sí esos datos (ya limpios y ordenados) enviarlos a Excel para su almacenamiento / análisis.
Luis me dice que tiene estos registros dentro del TXT:
dentro de el se describen una serie de actividades diarias
Y quiere enviar a otro archivo de texto solo la cantidad de horas dormidas:
en esta imagen podemos apreciar solo los valores numéricos correspondientes a las horas dormidas, las cuales deben quedar guardadas en un nuevo TXT
[+/-] Ver el resto / OcultarExisten muchas formas de llevar a cabo esta labor. Intentaré exponer la mas sencilla de ellas, con los datos que me brinda Luis. Antes de finalizar el post irán algunos consejos para optimizar el almacenamiento de registros, desde mi perspectiva, la cual es simplemente una más.
Pasos lógicos a seguir:
1) Abrimos el primer archivo de texto.
2) Recorremos los registros buscando la palabra "duermo", que será aquella que nos indicará que estamos frente a la línea de texto que contiene la info que buscamos (ej: "duermo 8 horas", "duermo 7 horas"). Esta palabra ("duermo") será de vital importancia, ya que actuará como "bandera" y nos alertará que ahí están los datos deseados.
3) Tomar nota de las horas dormidas
4) Guardar las horas dormidas en el segundo archivo de texto.
Abrimos Excel y con Alt + F11 vamos al editor de VBA, e insertamos un nuevo módulo, pengando en el este código:
Sub DosArchivosDeTexto() Dim Ruta1, Ruta2, Texto, Horas As String Dim Cont As Long Dim Matriz 'defino la ubicación de ambos archivos de texto. 'el archivoOriginal deberá existir o nos arrojará 'error: Ruta1 = "F:\archivoOriginal.txt" Ruta2 = "F:\archivoNuevo.txt" Cont = 0 'abro ambos archivos. el original en modo Input '(lectura) y el nuevo en modo Output (escritura, 'que elimina los datos existentes) Open Ruta1 For Input As #1 Open Ruta2 For Output As #2 'recorro los registros del txt original While Not EOF(1) 'almaceno la linea en la variable Texto Line Input #1, Texto 'si Texto empieza con "duermo" If LCase(Left(Texto, 6)) = "duermo" Then 'creo una matriz con la linea de texto Matriz = Split(Texto, " ") 'y guardo en el segundo txt la posi 'cion de la matriz que contiene la 'hora: Print #2, Matriz(1) Cont = Cont + 1 End If Wend Close #2 Close #1 'y el clásico mensaje de aviso: MsgBox "Se ha/n migrado " & Cont & " registro/s de horas dormidas", vbInformation End Sub
Y funciona, tal lo solicitado por Luis, pudiendo observar el resultado en las dos imágenes colocadas al principio del presente post.
Creo que esto tiene un punto débil: todo depende de que nuestra macro encuentre correctamente la palabra "duermo". si, por error, Luis u otros usuarios ingresan "duemo" o "duerno" el bloque "if ..." será incapaz de detectar en que línea del archivo de texto se encuentran las horas dormidas.
Una buena alternativa sería codificar cada actividad, lo que nos disminuiría bastante las probabilidades de error en el ingreso de datos. Por ejemplo:
Luego podríamos estructurar la información dentro del primer archivo de texto de la siguiente forma:
Explicado esto y el código, notarán que utilicé dos variables para almacenar la ruta de acceso a los archivos de texto. Si bien es cómodo, deberemos modificar este dato según donde se encuentre nuestro archivo original y donde querramos guardar el resultado. Existe una forma mucho mas elegante y práctica, que describiré a continuación y, ahora que me avivo, será tema de algún futuro post: los FileDialogs, o sea los cuadros de "abrir" y "guardar" archivos presentes en Windows. Podemos invocarlos desde VBA y así que nuestros usuarios seleccionen con que Files trabajarán.
El código completo, con sus respectivos comentarios para facilitar la lectura e interpretacion:
Te dejo el link para bajar el archivo de ejemplo.
Espero que te sea de utilidad, cualquier cosa me avisas. Salu2.xls
Creo que esto tiene un punto débil: todo depende de que nuestra macro encuentre correctamente la palabra "duermo". si, por error, Luis u otros usuarios ingresan "duemo" o "duerno" el bloque "if ..." será incapaz de detectar en que línea del archivo de texto se encuentran las horas dormidas.
Una buena alternativa sería codificar cada actividad, lo que nos disminuiría bastante las probabilidades de error en el ingreso de datos. Por ejemplo:
código 1 = me levanto
código 2 = trabajo
código 3 = duermo
código 4 = almuerzo
Luego podríamos estructurar la información dentro del primer archivo de texto de la siguiente forma:
1-6
3-8
4-13
siendo así que: me levanto a las 6, duermo 3 horas y almuerzo a las 13:00. Es mas complicada su lectura, pero estimo nos ahorrará muchos errores y nos permitirá manejar mejor los datos. Pero ojo, esto es relativo, ya que dependerá de las necesidades y características del proyecto.Explicado esto y el código, notarán que utilicé dos variables para almacenar la ruta de acceso a los archivos de texto. Si bien es cómodo, deberemos modificar este dato según donde se encuentre nuestro archivo original y donde querramos guardar el resultado. Existe una forma mucho mas elegante y práctica, que describiré a continuación y, ahora que me avivo, será tema de algún futuro post: los FileDialogs, o sea los cuadros de "abrir" y "guardar" archivos presentes en Windows. Podemos invocarlos desde VBA y así que nuestros usuarios seleccionen con que Files trabajarán.
así se verá el form para seleccionar el archivo de texto
El código completo, con sus respectivos comentarios para facilitar la lectura e interpretacion:
Sub DosArchivosDeTexto() Dim Ruta1, Ruta2, Texto, Horas As String Dim Cont As Long Dim Matriz 'almaceno en Ruta1 el valor que me devuelva la 'funcion creada: Ruta1 = ObtenerRuta 'si el usuario presionó "cancelar" salgo del 'sub, dado que me falta el archivo de origen 'por que no fué correctamente seleccionado: If Ruta1 = "" Then Exit Sub End If 'a la ruta2 la dejo fija, ya que será nuestra 'base de datos y, generalmente, deberá estar 'siempre en el mismo lugar Ruta2 = "F:\archivoNuevo.txt" Cont = 0 'abro ambos archivos. el original en modo Input '(lectura) y el nuevo en modo Output (escritura, 'que elimina los datos existentes) Open Ruta1 For Input As #1 Open Ruta2 For Output As #2 'recorro los registros del txt original While Not EOF(1) 'almaceno la linea en la variable Texto Line Input #1, Texto 'si Texto empieza con "duermo" If LCase(Left(Texto, 6)) = "duermo" Then 'creo una matriz con la linea de texto Matriz = Split(Texto, " ") 'y guardo en el segundo txt la posi 'cion de la matriz que contiene la 'hora: Print #2, Matriz(1) Cont = Cont + 1 End If Wend Close #2 Close #1 'y el clásico mensaje de aviso: MsgBox "Se ha/n migrado " & Cont & " registro/s de horas dormidas", vbInformation End Sub Function ObtenerRuta() As String 'declaramos una variable del tipo FileDialog Dim fd As FileDialog 'creamos el FileDialog, indicando que es para seleccionar 'archivos (FilePicker) Set fd = Application.FileDialog(msoFileDialogFilePicker) 'trabajamos con fd: With fd 'limpio cualquier filtro existente .Filters.Clear 'y agrego un filtro que solo muestre los archivos de texto .Filters.Add "Solo archivos de texto", "*.txt" .Filters.Add "Archivos de texto", "*.txt", 1 'desactivamos la option para seleccionar multiples archivos .AllowMultiSelect = False 'y personalizamos un poco el formulario: .Title = "Archivos de texto horas dormidas" 'si el usuario seleccionó un archivo de texto, devuelvo su ruta: If .Show = -1 Then ObtenerRuta = fd.SelectedItems(1) Else 'si presionó cancelar aviso y retorno una cadena vacía: MsgBox "No ha seleccionado ningún archivo, la macro se cancela", vbExclamation ObtenerRuta = "" End If End With 'destruyo la variable, para liberar recursos Set fd = Nothing End Function
Te dejo el link para bajar el archivo de ejemplo.
Espero que te sea de utilidad, cualquier cosa me avisas. Salu2.xls
- Obtener enlace
- Correo electrónico
- Otras aplicaciones
Etiquetas
Macros
Etiquetas:
Macros
- Obtener enlace
- Correo electrónico
- Otras aplicaciones
Qué grande eres Damián!
ResponderEliminarMe has ahorrado mucho tiempo de investigación puesto que yo justo acabo de adentrarme en esto de las macros y estoy bastante perdido.
He conseguido adaptar tu código a mi caso concreto. Sólo me quedaba un detalle por solucionar pero mientras te escribía la duda se me encendió la luz.
Entiendo que lo que se hace con Split es segmentar las cadenas de texto encontradas con la palabra "duermo" en columnas separadas por un carácter o caracteres concretos, en nuestro caso el carácter espacio " ". Mi problema es que yo necesitaba en realidad lo que había después del segundo espacio. Entonces he cambiado Matriz (1) por Matriz (2) y ha dado resultado. En el ejemplo lo que obtendríamos sería este texto:
horas
horas
horas
Continúo con mi proyecto. Seguramente me vea obligado a consultarte algo más.
Muchas gracias.
Saludos.
perfecto, te agradezco mucho que me avises y también tus palabras. no dudes en consultarme sobre lo que necesites.
ResponderEliminarefectivamente Split(cadena, delimitador) convierte una cadena de texto en una matriz. en tu ejemplo, y para separar cada elemento y colocarlo dentro de un espacio en el array, utilizamos el espacio en blanco ( " " ), pero podría ser cualquier caracter.
si tengo la cadena: "a-b-c-d" y hago:
Matrix = Split("a-b-c-d", "-") obtengo la matriz:
a
b
c
d
y puedo acceder a cualquier elemento.
es una alegría saber que el ejemplo te sirvió.
salu2.xls
ahora que releo tu entrada noto algo extraño... pero bueno, si te funciona, dejalo así.
ResponderEliminarte comento: todos los índices de las matrices en visual basic se inicializan en 0 (cero). o sea que si tengo una matriz con 5 elementos se codificaría de la siguiente forma:
matrix(0)
matrix(1)
matrix(2)
matrix(3)
matrix(4)
en tu caso llevo la cadena:
duermo 7 horas
a una matriz de 3 elementos, con Split()
me queda:
matrix(0)=duermo
matrix(1)=7
matrix(2)=horas
¿me seguís? por eso en mi ejemplo puse
matrix(1)
ya que la segunda posición de la matriz (que la identifico con el numero 1, por que todas las matricies inicializan en cero) es la correspondientes a las horas. quizas en tu archivo exista algún espacio de texto adicional y por eso debiste cambiarle el índice.
o bien, y problablemente sea esto, en algún módulo tenes la instrucción "Option Base 1", que fuerza a visual basic a inicializar todas las matrices con el índice 1, en lugar de cero.