18.5.06

Extrayendo fragmentos de frases con expresiones regulares

Saludos.

Recientemente, desarrollando unas herramientas de prueba, me he encontrado la necesidad de extraer fragmentos de frases compuestas. Lo que buscaba era poder hacer algo así. Si tengo, por ejemplo, estas dos frases.

1: El niño cogió la pelota con las manos.
2: El niño de azul cogió la pelota grande y morada con las dos manos.

Y quiero aplicar el siguiente patrón.

El $1 cogió $2 con $3

El resultado que quiero es:

1: $1 = "niño", $2 = "la pelota", $3 = "las manos"
2: $1 = "niño de azul", $2 = "la pelota grande y morada", $3 = "las dos manos"


Por suerte encontré una manera rápida y fácil de hacer esto en Java con expresiones regulares y Jakarta RegExp (http://jakarta.apache.org/regexp/index.html). Con esta herramienta escribo el patrón utilizando una expresión regular y encerrando entre paréntesis las expresiones que luego quiero recuperar. Así, el patrón anterior se expresaría de la siguiente forma:

El (.+) cogió (.+) con (.+)

El código para aplicar las frases anteriores al patrón se muestra a continuación.



import org.apache.regexp.*;

public class DemoBlog {

public static void main(String[] args) {

String f1 = "El niño cogió la pelota con las manos.";
String f2 = "El niño de azul cogió la pelota grande y morada con las dos manos.";
String re00 = "El (.+) cogió (.+) con (.+)";

RE re = new RE(re00);
System.out.println("Match: " + re.match(f1) );
System.out.println("Match: " + re.match(f2) );
}
}




El código anterior nos muestra por consola que ambas frases casan con la expresión regular.

Ahora, para extraer la parte de la frase que casa con cada una de las expresiones entre paréntesis del patrón, solo tenemos que llamar a getParen(índice), con índice = 1 para obtener el primer paréntesis e índice = 3 para el último. Por ejemplo:


System.out.println("$1 = " + re.getParen(1) );
System.out.println("$2 = " + re.getParen(2) );
System.out.println("$3 = " + re.getParen(3) );


Además, índice = 0 nos devuelve todo el texto (en este caso la frase completa). Si no queremos saber a priori cuanto paréntesis tenemos, podemos ir llamando a getParen(índice) hasta que este nos devuelva null.


Las clases de expresiones regulares (java.util.regexp) que viene a partir del SE 1.4 (y que comentamos en el post de pruebas con JUnit y expresiones regulares) no permiten hacer lo mismo. O, al menos, yo no he encontrado ninguna manera de hacerlo.

También estuve mirando el proyecto ORO de Jakarta (http://jakarta.apache.org/oro/index.html), por si tuviera algo que me permitiera hacer esto mismo de una manera más potente. Pero en un primer vistazo no he visto nada interesante.

8.5.06

Rompiendo una lanza a favor de las empresas de informática

Saludos.

Algunas veces escuchamos, o leemos, comentarios de que en tal o cual empresa se escriben aplicaciones deficientes y código malo. La causa principal, dicen, es la falta de tiempo. n las empresas hay que hacerlo ya, y por eso no hay tiempo para hacer una buena planificación y un buen diseño.

No creo que eso sea una buena justificación para hacer mal código. A continuación juego de abogado del diablo y expongo el por qué.

Dudo mucho que a un arquitecto le pidan el diseño de una torre o unos chalets y le digan que el tiempo no importa, que tarde lo que le apetezca. Lo mismo les pasa a los albañiles, seguro que ellos no tienen tiempo para planificar cómo van a poner los ladrillos. Sin embargo, los edificios no se caen, ni la gente deja de usarlos porque son inhabitables, ni hay que llamar constantemente a arquitectos y albañiles para que pongan parches.

A nadie se le ocurre que, por mucha prisa que haya en levantar un edificio, los albañiles comiencen a poner ladrillos por su cuenta. ¿por qué?. Pues porque los arquitectos, los albañiles, y tantos otros profesionales, saben hacerlo rápido y hacerlo bien.


Esto es algo que, según mi opinión, los informáticos aún no sabemos hacer. Si no hay tiempo para hacer un buen diseño, hay que hacer un buen diseño sobre la marcha.

Cuando escribamos el código debemos Ser capaces de identificar rápidamente las necesidades y decidir qué clases construir. Debemos tener muy en cuenta algunos conceptos de diseño fundamentes como las clases tímidas o la encapsulación (pedir a los objetos que hagan operaciones, en vez de pedirles información para hacerlo nosotros). Tampoco debemos olvidar los patrones, por ejemplo, utilizar siempre el patrón iterador (IEnumerator en .NET) para recorrer colecciones de objetos, o implementarlo para nuestras propias colecciones. Si Java y .NET o hacen, ¿por qué no nosotros?. Tampoco hay que escribir tanto código.

Desde mi opinión, la mayoría de las personas que empiezan en las empresas de informática, vengan de la universidad, de FP, de cursos de formación o autodidactas, no saben hacer estas cosas (incluso algunas que llevan muchos años si no se esfuerzan en mejorar). Aunque también tengo mi opinión de por qué pasa esto, no voy a entrar en ese debate.

Si nos formamos adecuadamente y ponemos en práctica lo aprendido nuestro código no va a ser bueno a la primera y cometeremos errores. Pero seguro que esos errores serán más pequeños y fáciles de arreglar (encapsular / desacoplar, encapsular / desacoplar, encapsular / desacoplar,....). Seguro que nuestro código es muchísimo mejor y seguro que

podremos ir convenciendo a nuestros jefes de que, si le dedicamos algo de tiempo al principio, nuestro código será aún mejor, seremos más productivos y más rápidos.

En resumen, si sabemos hacerlo bien, hacerlo rápido sólo implica pensar más rápido. Hacerlo mal nunca es hacerlo rápido.

Termino con otra opinión que, en principio, puede parecer que no tenga mucha relación pero creo que la tiene. Un sueldo bajo no debe ser excusa para hacer mal nuestro trabajo.

PD:

Por supuesto, esto es una opinión personal algo "extrema" y provocadora. Ni esto es la causa de todos los males ni su solución. Por descontado cualquier otra opinión a favor o en contra es bienvenida.