sábado, 18 de junio de 2016

Visual Studio. Buscar y reemplazar con expresiones regulares.

Seguro que las funciones de "Buscar" y "Buscar y reemplazar" del Visual Studio se encuentran entre las funciones que más utilizas dentro del entorno de desarrollo. Sin embargo, si no estás haciendo uso de la posibilidad de usar expresiones regulares, estás utilizando una parte mínima de la potencialidad de estas funciones.

En este post voy a mostrar un ejemplo de cómo puedes realizar búsquedas y cambios masivos en tu código gracias al uso de expresiones regulares.

Créeme, aunque te parezca que usas mucho estas opciones, no es nada comparado con lo que las utilizaras una vez que cojas un poco de soltura con las expresiones regulares,

Hace poco, por ejemplo, en el proyecto en el que me encuentro decidimos establecer como privadas una serie de funciones que definíamos como públicas en cientos de objetos JavaScript diferentes de nuestra aplicación. Un "Buscar y reemplazar" con una expresión regular y listo, en unos segundos estaba hecho el cambio, ahorrándonos un montón de horas de tedioso y mecánico trabajo.



Imaginemos que tenemos un montón de sentencias LINQ en nuestro código en las que, para comprobar si existen registros que cumplen una condición, ejecutamos un método Where para filtrar los datos y a continuación el método Any para comprobar si la condición ha devuelto algún resultado.

bool HayArticulosRojos = Articulos.Where(a => a.Color == Color.Red).Any();

Para simplificar nuestro código nos hemos propuesto simplificar estas sentencias con una única llamada al método Any:

bool HayArticulosRojos = Articulos.Any(a => a.Color == Color.Red);

Puede parecer un cambio poco práctico pero para el ejemplo nos servirá perfectamente.

Como código de ejemplo de nuestra aplicación utilizaremos por ejemplo éste:

 IEnumerable<Articulo> articulos = new List<Articulo>();
 IEnumerable<Persona> personas = new List<Persona>();
 
 if (personas.Where(p => p.Nombre == "MiProveedor").Any())
 {
     bool hayArticulosRojos = articulos.Where(a => a.Color == Color.Red).Any();
     bool hayArticulosCaros = articulos.Where(art => art.Precio > 4000).Any();
     bool hayArticulosSinPrecio = articulos
         .Where(art => art.Precio == 0)
         .Any();
     var articulosSeleccionado = articulos
         .Where(a => a.Proveedores.Any(p => p.Nombre == "Mi Proveedor"));
 }

El código en sí no tiene mucho sentido pero tiene todo lo que necesitamos para el ejemplo.

Tenemos consultas que cumplen el patrón que queremos buscar realizadas sobre diferentes objetos y con diferentes condiciones. La primera consulta está definida dentro de un if mientras que el resto se asignan directamente a variables.

Incluso una de las consultas está dividida en varias líneas de código. Otra de las ventajas de las expresiones regulares: nos permite localizar código que no tiene porqué encontrarse en una misma línea.

La última consulta, aunque hace uso de los métodos Where y Any, no se ajusta al patrón que deseamos buscar por lo que no debería seleccionarse en nuestra búsqueda.


Buscar con expresiones regulares


Lo primero que deberemos hacer es definir la expresión regular que define el patrón que debemos localizar.

La expresión que utilizaremos es: \.Where\([^\)]+\)[\s\n]*\.Any\(\)

Para más información sobre el uso de Expresiones Regulares puedes acudir a la documentación de MSDN:
Lenguaje de expresiones regulares - Referencia rápida

Para comprobar que la expresión regular funciona correctamente usaremos el diálogo de "Búsqueda rápida" de Visual Studio. En este diálogo deberemos activar el botón correspondiente a las expresiones regulares cuyo icono está formado por un punto y un asterisco:

Búsqueda rápida

Como podemos ver la búsqueda nos selecciona todas las condiciones que cumplen el patrón establecido, incluso la que está dividida en dos líneas diferentes.

Ya podríamos realizar una búsqueda en todo el código de nuestra solución. En el diálogo "Buscar en Archivos" deberemos activar la opción "Usar expresiones regulares" dentro de la sección "Opciones de búsqueda":

Buscar en archivos

Buscar y reemplazar


Pero una cosa es encontrar el código a reemplazar y otra muy distinta conseguir reemplazarlo de forma automática.

En este caso nos encontramos con un problema que nos resultaría insalvable sin utilizar expresiones regulares: debemos incluir parte del código encontrado (la condición del Where) en el resultado (en la condición del Any), y éste código no es fijo.

Podemos resolver este problema fácilmente porque Visual Studio nos ofrece la posibilidad de incluir texto capturado a través de la expresión regular en el texto a reemplazar.

Para poder hacerlo, lo primero que tenemos que hacer es establecer el texto a capturar en a expresión regular, en nuestro caso: el texto correspondiente a la condición del Where.

La forma de realizar una captura en las expresiones regulares es encerrar el texto a capturar entre paréntesis. De esta forma la expresión regular quedaría como: \.Where\(([^\)]+)\)[\s\n]*\.Any\(\). Lo que he hecho es encerrar entre paréntesis el texto correspondiente a a condición: ([^\)]+).

La forma de incluir un texto capturado en el texto de reemplazo es utilizando la sintaxis $<nº de captura>. Es decir, si tenemos por ejemplo tres capturas en la expresión regular, éstas podrán incluirse como $1, $2 y $3. Como en nuestro caso tenemos una única captura ésta se incluiría como $1.

Así, definiremos el texto de sustitución como: .Any($1).

Si abrimos el diálogo "Reemplazar en archivos" y establecemos los valores del campo "Buscar" (con la expresión regular) y "Reemplazar por" (con .Any($1)). Podremos realizar la sustitución masiva. Hay que recordar también activar la opción "Usar expresiones regulares" en las "Opciones de búsqueda".

En la siguiente imagen podemos ver el resultado:

Buscar y reemplazar


No hay comentarios:

Publicar un comentario