Vamos a tratar en esta
entrada las expresiones regulares en Java. Será sólo una
aproximación, porque esto de las expresiones regulares, regex para
abreviar, es un lenguaje en sí mismo y da para varios libros. Las
expresiones regulares no se utilizan sólo en Java, si no también en
otros lenguajes de programación, como Pearl o Groovy, y por supuesto
las puedes usar en Word o Writer. Sin embargo, en cada lenguaje
existen ligeras diferencias a la hora de usarlas. Como si no fuera ya
bastante complicado el tema. Lo que sí tienen en común es que se
usan para encontrar y manipular texto.
Una expresión regular
sustituye desde un simple carácter a oraciones enteras que deseas
encontrar en un texto. Evidentemente, si quieres encontrar más de
una palabra, o incluso una palabra larga, no es muy práctico tener
que escribirlas literalmente.
Java tiene dos clases,
dentro del paquete java.util.regex, especializadas en este tipo de
manipulación de texto: Matcher y Pattern. Pattern compila una
expresión regular para crear un patrón. Matcher utiliza dicho
patrón para hallar coincidencias en el texto.
Por ejemplo:
String texto =
“Este es el texto en el que vamos a buscar un patrón”;
String patrónDeTexto
= “.*el.*”; //.* significa cero o más caracteres antes y
después de la palabra.
Pattern patrón =
Pattern.compile(patrónDeTexto); //creamos una instancia de Pattern
Matcher match =
patrón.matcher(texto); //creamos una instancia de Matcher
boolean b =
match.matches();
System.out.println(“Coincide: “+ b);
Si la expresión
regular sólo la vamos a usar una vez, podemos utilizar el método
matches() con Pattern sin necesidad de una instancia de Matcher,
simplificando lo anterior así:
String texto =
“Este es el texo en el que vamos a buscar un patrón”;
String patrónDeTexto
= “.*el.*”;
boolean b =
Pattern.matches(patrónDeTexto, texto);
System.out.println(“Coincide: “+b);
lo que nos daría la
misma salida que en el caso anterior:
Coincide: true
Supongamos ahora que
queremos saber exáctamente cuántas coincidencias hay en el texto de
la palabra “el” y en qué lugar se encuentran. Para ello
utilizaremos los métodos de Matcher find(), start() y end(),
teniendo en cuenta que el índice comienza en cero y que los espacios
en blanco también cuentan como caracteres.
String texto =
“Este es el texto en el que vamos a buscar un patrón”;
String
patrónDeTexto = “el”; //queremos saber cuántas veces aparece
esta palabra.
Pattern patrón =
Pattern.compile(patrónDeTexto);
Matcher match =
patrón.matcher(texto);
int contador = 0;
while
(match.find()){
contador++;
System.out.println(“Coincidencia: “ + contador + “ de ” +
match.start() + “ a ” + matcher.end());
}
La salida en este caso
será la siguiente:
Coincidencia: 1 de
8 a 10
Coincidencia: 2 de
20 a 22
Otro método
interesante es split(), utilizado para separar el texto en distintas
líneas, de esta manera:
String texto =
“Este es el texto, en el que vamos a buscar, un patrón”);
String
patrónDeTexto = “,”;
Pattern patrón =
Pattern.compile(patrónDeTexto);
String[] split =
patrón.split(texto);
for(String palabras
: split){
System.out.println(palabras);
}
La salida en este caso
es:
Este es el texto
en el que vamos a
buscar
un patrón
Hasta ahora hemos
visto unos cuantos métodos de las clases Pattern y Matcher, pero
poco sobre las expresiones regulares en sí. Pero como ya hemos
dicho, utilizar expresiones literales suele ser muy inconveniente.
Veamos ahora algunas de las expresiones regulares más utilizadas en
Java.
. equivale a
cualquier carácter
\d equivale a
cualquier dígito
\D equivale a
cualquier carácter no dígito
\s equivale a un
espacio en blanco
\S equivale a
cualquier carácter excepto un espacio en blanco
\w equivale a
cualquier letra
\W equivale a
cualquier carácter excepto letras
[abc] equivale a a,
b o c (o cualquier otro carácter que se indique)
[^abc] equivale a
cualquier carácter excepto a, b o c
[a-zA-Z] equivale a
cualquier carácter de la a a la z o de la A a la Z, todos inclusive
[a-d[m-p]] equivale a
cualquier carácter de la a la d o de la m a la p
[a-z&&[def]]
equivale a d, e o f
[a-z&&[^bc]]
equivale a cualquier carácter de la a a la z excepto b o c
[a-z&&[^m-p]]
equivale a cualquier carácter de la a a la z excepto los que van de
la m a la p
Además, en java regex
se utilizan cuantificadores para indicar el número de veces que se
repiten los caracteres buscados. Estos cuantificadores se denominan
greedy, reluctant y possessive. Para indicar el cuantificador greedy,
siendo X un carácter cualquiera, se escribe:
X* para buscar
coincidencias de cero o más X
X? para buscar
coincidencias de una o ninguna X
X+ para buscar
coincidencias de una o más X
Para denotar el
cuantificador reluctant, a los signos anteriores se añade ?, de esta
manera:
X*?
X??
X+?
Y para el
cuantificador possessive, el signo +:
X*+
X?+
X++
¿Cómo funcionan
estos cuantificadores? Bueno, el cuantificador greedy “lee” todo
el texto de una vez y luego, de derecha a izquierda, se va
deshaciendo de caracteres y vuelve a leer lo que queda una y otra vez
hasta encontrar una coincidencia. El cuantificador reluctant, en
cambio, empieza leyendo el texto de iquierda a derecha hasta hallar
la coincidencia buscada. El cuantificador possessive lee el texto
entero como el greedy, pero solo una vez, y si no haya una
coincidencia esa vez, no sigue buscando más.
Veamos esto con un
ejemplo. Supongamos que tenemos el siguiente texto “ID usuario
Nombre usuario” y buscamos cero o más coincidencias de la
siguiente expresión regular .io(cualquier carácter seguido de io)
Greedy: .*io. Leería
el texto entero, que no está seguido de io, e iría “soltando”
caracteres hasta que encontrase ID usuario Nombre usuar, seguido de
los caracteres io que habría soltado y encontraría una
coincidencia:
ID usuario Nombre
usuario.
Reluctant: .*?io. Iría
leyendo el texto de izquierda a derecha y encontaría dos
coincidencias:
ID usuario
Nombre usuario
Possessive: .*+io.
Leería todo el texto, pero solo una vez, y claro, como el texto no
está seguido de io, no encontaría ninguna coincidencia.
Como hemos dicho, esto solo es una breve aproximación a las expresiones regulares en Java, pero esperamos que os sirva para ir practicándolas, así como a entender cómo funcionan las clases Pattern y Matcher.
No hay comentarios:
Publicar un comentario