Eliminar filas en blanco con macro

Eliminar filas en blanco mediante VBA

En estos días estoy trabajando en la importación de datos desde un pdf. Este archivo consta de más de 500 páginas de listado de datos. Aunque se puede elaborar más, la solución sencilla que estoy aplicando es abrir el pdf, copiar todo el contenido en el portapapeles y pegarlo a partir de una celda como texto. Esto genera más de 45.000 filas con datos buenos mezclados con otros que no me sirven y con líneas en blanco, que debo eliminar.

El problema es que al copiar el archivo completo, hay filas que tienen texto del encabezado de cada página e incluso los números de página. Por supuesto, esa información me sobra. También hay muchas filas en blanco. Así que me he programado una macro para eliminar las filas que me sobran, empezando por las filas en blanco. Imaginemos que lo que estamos copiando es un diccionario español-inglés de términos médicos. Se puede observar que hay líneas en blanco, líneas de título e incluso los números de página.

eliminar filas
A la izquierda, pdf. A la derecha, la misma posición tras copiar a Excel.

Para establecer los criterios indicaré que los datos los he copiado en la celda A10, y se extienden hacia abajo hasta que terminan. El código es fácil:

Sub borrafilas()
Dim fila As Long
Dim max As Long                        'Si vamos a pasar de 32.767 filas no nos vale Integer

fila = 10
Range("A1048576").End(xlUp).Select         'Selecciono la última celda de la hoja y subo hasta la última celda con datos
max = Selection.Row

 Do While fila < max                       'repite el bucle mientras no se alcance la última fila
     If Cells(fila, 1) = 0 Then                'Si la celda está vacía
         Cells(fila, 1).EntireRow.Delete
         max = max - 1                                  'disminuimos la última fila porque hemos eliminado una por medio,
                                                                     'para eliminar un bucle infinito al final
     Else
         fila = fila + 1
     End If
 Loop
End Sub

Explicación

La macro está muy bien, hemos aplicado un par de trucos o tres.

Truco 1: declarar variables

Si las variables las hubiéramos declarado como Integer, entonces la macro casca si, como era mi caso, tienes más de 32.767 filas. Por lo tanto, he declarado las variables como Long.

Puedes pensar que no hace falta declarar las variables, pero yo opino que para tener el control sobre lo que está haciendo el programa, hay que declarar explícitamente todas las variables.

Truco 2: Limitar las iteraciones

Como puedes ver en el código, cada vez que elimino una fila también reduzco el valor máximo de la última fila a comprobar. Esto es porque más allá de la última fila, todas las celdas están vacías, y si no reduzco el límite, generaré un bucle infinito.

En ocasiones modifico el criterio de finalización. En vez de poner un número máximo de iteraciones que voy corrigiendo sobre la marcha, lo que hago es manualmente escribir en la celda debajo de la última algo como “FIN” y comprobar eso en el bucle WHILE.

 Do While Cells(fila,1).value <> "FIN"

Pero esto obliga a hacer un paso manual. Y ¿por qué hacer cosas a mano cuando Excel puede hacerlas por nosotros?

Truco 3: No saltarnos filas al eliminar

Cuando eliminamos una fila, la siguiente ocupa su puesto. Si incrementamos el contador en todas las iteraciones, entonces al eliminar una fila no procesaríamos la que sube y ocupa el lugar de la que acabamos de eliminar. Por eso solo aumento el contador cuando no se elimina ninguna fila.

Pongamos por ejemplo que la fila 15 la procesamos. Como consecuencia, cumple los criterios y la eliminamos. Por lo tanto, la que antes era la 16 ha subido y ahora es la 15. Eso significa que en nuestra siguiente iteración debemos procesar la fila 15 de nuevo, porque ahora tiene otros datos. Esta es la razón principal para no utilizar un bucle FOR.

Truco 4: No seleccionar celdas

Hay una tentación, que es seleccionar las celdas que vamos a procesar, así:

Cells(fila,1).select
Selection.EntireRow.Delete

o

Range("A" & fila).select
Selection.EntireRow.Delete

Esto no tiene ninguna utilidad práctica, y lo que sí hace es ralentizar bastante el funcionamiento de la macro.

Algunas mejoras más

De momento la macro funciona bastante bien, pero si hay muchos datos que cumplan el criterio y tenemos que eliminar muchas filas, Excel se tomará un buen rato mientras parece que se ha quedado colgado. Nos queda algún truco más.

ScreenUpdating

Siempre que vayas a ejecutar una macro que hace muchas cosas sobre las hojas, como por ejemplo eliminar filas, conviene utilizar una orden que facilita las tareas:

Application.ScreenUpdating = false

Se sitúa al principio de la macro, y hace lo siguiente:

Cuando ScreenUpdating es false, Excel no escribe los cambios en pantalla cada vez que ocurren. En nuestro caso, al eliminar una fila se produce una animación que elimina la fila y que desplaza las restantes hacia arriba. Esa animación consume tiempo y recursos. Si bien es muy poco, cuando hay que repetirlo miles de veces puede convertirse en bastante. Lo mismo ocurre cuando hay que cambiar un valor en una celda. Hay una animación que elimina el valor antiguo y dibuja en pantalla el nuevo.

Cuando ScreenUpdating es true, Excel funciona como lo hace normalmente en modo manual. Aunque Excel cambia el valor a VERDADERO al terminar la ejecución de la macro, conviene escribirlo explícitamente al final de nuestro código por el bien de la legibilidad.

Application.ScreenUpdating=true

EnableEvents

En el caso de que nuestra hoja capture eventos sobre las celdas (Activate, SelectionChange, BeforeDelete, Calculate…) y en nuestro código hagamos cosas que puedan lanzar estos eventos, es posible que no nos interese que se lancen automáticamente.

Por poner un ejemplo, supongamos que tenemos un código escrito en BeforeDelete que realiza unas comprobaciones antes de eliminar cualquier celda. Pero nosotros ya hemos realizado nuestras comprobaciones para eliminar las filas, por lo que no nos interesa que se lance BeforeDelete mientras se ejecuta el código de borrafilas(). En este caso escribiremos al principio lo siguiente:

Application.EnableEvents=false

Este código hay que utilizarlo con mucho cuidado. Es muy importante asegurarnos de que una vez se ejecuta, finalmente se dejarán las cosas como estaban, es decir, al final siempre hay que escribir:

Application.EnableEvents=true

De lo contrario, no se volverán a lanzar eventos hasta que se vuelvan a habilitar, es decir, no se ejecutarán más macros respondiendo a una pulsación de un botón, una modificación de una celda, etc.

Aun así, si se produce un error no se nos reactivarán los eventos. Por eso suelo capturar los errores de la siguiente manera:

On error GoTo SalidaLimpia
.
.   {todo el código de la macro}
.
SalidaLimpia:
Application.EnableEvents=true
.
.   {otras cosas que quiera dejar cerradas en cualquier caso}

Referencias

Puedes encontrar más información en los siguientes enlaces:

(Visited 53.480 times, 1 visits today)

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información ACEPTAR

Aviso de cookies