Bienvenidos sean a este post, hoy hablaremos sobre las expresiones regulares en Java.
Estas son una secuencia especial de caracteres que sirven para encontrar o coincidir otras cadenas o conjunto de cadenas usando una sintaxis especializada contenida en una patron. Esta funcion esta provista mediante el paquete java.util.regex; y estas pueden ser usadas para buscar, editar y manipular texto y datos. Este paquete contiene principalmente estas tres clases:
- Pattern class: un objeto modelo es una representacion compilada de las expresiones regulares, esta clase no provee constructores publicos, para crearlo primero debes invocar una de las metodos publicos estaticos de compile(), el cual retornara un objeto modelo (pattern) y estos metodos aceptan una expresion regular como primer argumento.
- Matcher class: un objeto de esta clase es el motor encargado de interpretar el modelo (pattern) y ejecuta operaciones de coincidencia contra una cadena de entrada, como la clase anterior tampoco declara constructores publicos, este objeto se logra por medio del metodo matcher() sobre un objeto modelo (pattern)
- PatternSyntaxException: el objeto creado de esta clase es una excepcion sin chequear que devuelve un error de sintaxis en un modelo de expresion regular.
Pasemos a hablar sobre los grupos de captura, estas son una forma de tratar multiples caracteres como una unidad simple. Para lograr esto se ponen los caracteres agrupados dentro de un conjunto de parentesis. Los grupos se cuentan con los parentesis de izquierda a derecha, por ejemplo:
((A)(B(C))), contiene cuatro grupos. Puedes utilizar el metodo groupCount() en el objeto matcher, este metodo retorna un valor de tipo int mostrando la cantidad de grupos, veamos ahora la sintaxis de una expresion regular:
| Subexpresion | Coincidencia |
| ^ | Coincide con el comienzo de la linea |
| $ | Coincide con el final de la linea |
| . | Coincide con cualquier caracter excepto el de nueva linea |
| […] | Coincide cualquier caracter dentro de los corchetes |
| [^…] | Coincide cualquier caracter fuera de los corchetes |
| \A | Comienzo de la cadena entera |
| \z | Final de la cadena entera |
| \Z | idem al \z excepto por el terminador de la linea permitido |
| re* | Coincide con 0 o más apariciones de la expresión anterior. |
| re+ | Coincide con 1 o mas de lo anterior |
| re? | Coincide con 0 o 1 aparición de la expresión anterior. |
| re{ n} | Coincide exactamente n cantidad de veces de la expresion anterior |
| re{ n,} | Coincide n o mayor cantidad de veces de la expresion anterior |
| re{ n,m} | Coincide con al menos n y como máximo m ocurrencias de la expresión anterior. |
| a|b | Coincide con a o b |
| (re) | Agrupa expresiones regulares y almacena el texto coincidido |
| (?:re) | Igual al anterior pero sin recordar la coincidencia |
| (?>re) | Coincide con el patrón independiente sin retroceso. |
| \w | Coincide los caracteres de la palabra |
| \W | Coincide con los caracteres sin palabra |
| \s | Coincide con los espacios en blanco, equivalente a [\t\n\r\f] |
| \S | Coincide con los espacios no en blanco |
| \d | Coincide con los digitos, equivale a [0-9] |
| \D | Coincide con los no digitos |
| \A | Coincide con el comienzo de la cadena |
| \Z | Coincide con el final de la cadena pero justo antes de la nueva linea |
| \z | Coincide con el final de la cadena |
| \G | Coincide con el punto donde el ultimo encuentro termino |
| \n | Referencia para capturar el numero de grupo «n» |
| \b | Coincide con los límites de palabras cuando está fuera de los corchetes. Coincide con el retroceso (0x08) cuando está dentro de los corchetes. |
| \B | Coincide con los límites sin palabras. |
| \t,\n,\r,\f | Coincide con el tab, nueva linea, retorno, form feed |
| \Q | Escape (cita) todos los caracteres hasta \ E. |
| \E | Finaliza la busqueda comenzada con \ Q. |
Esta es la tabla que muestra toda la sintaxis de metacaracteres de expresión regular disponible en Java, pasemos a un pequeño ejemplo para entender un poco mejor el concepto de expresiones regulares:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches
{
public static void main (String args[])
{
String line = "Esta orden fue puesta por QT3000! Ok?";
String pattern = "(.*)(\\d+)(.*)";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(line);
if (m.find())
{
System.out.println("Valor encontrado: " + m.group(0) );
System.out.println("Valor encontrado: " + m.group(1) );
System.out.println("Valor encontrado: " + m.group(2) );
} else {
System.out.println("No hubo coincidencias");
}
}
}
En este caso importaremos dos paquetes, una de clase Matcher y otro de la clase Pattern. En el cuerpo de main crearemos dos variables de tipo String, una llamada line donde estara almacenada la cadena a analizar, y la variable pattern donde guardaremos los parametros de nuestra busqueda. Despues creamos un objeto de la clase Pattern llamado r y pueden ver como lo compilamos con las expresiones de busqueda. Nuestro siguiente objeto sera de la clase Matcher llamado m y ahi enviaremos el texto contenido en line. Despues vendra un condicional if donde por medio del metodo find() veremos si hay coincidencias. En caso negativo, mostrara un mensaje y en caso afirmativo nos devolvera tres lineas con los valores obtenidos de cada uno de nuestros grupos. Si lo compilamos y ejecutamos obtendremos la siguiente salida:
$ java RegexMatches
Valor encontrado: Esta orden fue puesta por QT3000! Ok?
Valor encontrado: Esta orden fue puesta por QT300
Valor encontrado: 0
$
Como pueden ver el primer grupo devuelve todo el texto, group(0), el segundo grupo devuelve hasta el digito que coincide mas de una vez. En el ultimo caso nos devuelve el ultimo digito coincidido por nosotros. Tambien observen que en el segundo grupo usamos \\d+ en lugar de \d+ esto es debido a que la barra invertida (\) es un caracter de escape de estos lenguajes y necesitamos aclararle que es un modificador de expresion regular.
Estos metodos proveen valores de indices utiles que muestran donde fue encontrada la coincidencia en la cadena de entrada, aqui esta el listado:
- public int start(): devuelve el indice inicial de la coincidencia previa.
- public int start(int grupo): devuelve el indice inicial de una subsecuencia capturada por el grupo dado de una coincidencia previa.
- public int end(): devuelve el ultimo lugar despues del ultimo caracter encontrado.
- public int end(int grupo): devuelve el ultimo lugar despues del ultimo lugar de la subsecuencia capturada por el grupo dado durante la operacion de coincidencia previa.
Despues tenemos los metodos de estudio (study) los cuales devolveran un valor booleano indicando si existe una coincidencia o no del patron informado, veamos algunos de los metodos utilizados:
| Metodo | Descripcion |
| public boolean lookingAt() | Intenta coinicidir la secuencia de entrada, comenzando por el prinicipio contra el patron |
| public boolean find() | Intenta encontrar la proxima secuencia de entrada que coincide con nuestro patron |
| public boolean find(int start) | Es igual al anterior pero lo hace desde le informemos |
| public boolean matches() | Intenta encontrar la region entera que coincide con el patron |
Otros metodos que disponemos son los de reemplazo, y son utilizados para reemplazar un texto en una cadena de entrada veamos una lista de metodos:
- public Matcher appendReplacement(StringBuffer sb, String reemplazo): implementa un paso de reemplazo y agregado no terminal
- public StringBuffer appendTail(StringBuffer sb): igual al anterior pero en este caso terminal
- public String replaceAll(String reemplazo): reemplaza cada subsecuencia de la cadena de entrada que coinicida con la cadena informada
- public String replaceFirst(String reemplazo): igual al anterior pero solamente reemplaza la primer coincidencia
- public static String quoteReplacement(String s): devuelve una cadena de reemplazo de la cadena informada, este dato obtenido es utilizado para informarla en el metodo appendReplacement().
Antes de pasar a ver unos ejemplos, hablemos sobre los metodos de la clase PatternSyntaxException. Esta es una excepcion sin chequear que indica errores de sintaxis en un patron de expresion regular, veamos la siguiente lista de metodos disponibles de esta clase para una descripcion del error:
- public String getDescription(): devuelve la descripcion del error
- public int getIndex(): devuelve el indice de error
- public String getPattern(): devuelve el patron de expresion regular erroneo
- public String getMessage(): devuelve una cadenda multilinea con todos los datos de los metodos anteriores
Con todos los metodos explicados pasemos a ver algunos ejemplos practicos de algunos metodos antes descriptos:
Los metodos start y end
RegexCoinc.java
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexCoinc
{
private static final String REGEX = "\\bcat\\b";
private static final String INPUT = "cat cat cat cattie cat";
public static void main( String args[])
{
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT);
int count = 0;
while(m.find())
{
count++;
System.out.println("Match number " + count);
System.out.println("start(): " + m.start());
System.out.println("end(): " + m.end());
}
}
}
En este ejemplo primero tendremos una expresion regular (REGEX), luego el texto a analizar (INPUT). Luego en el cuerpo de main definiremos dos objetos, uno de Pattern llamado p y otro de Matcher llamado m. En el primero compilamos la expresion y en el segundo usamos a matcher sobre el texto, despues definiremos una variable llamada count y le asignaremos el valor de cero. Luego hara un bucle en base al metodo find(), en el cual mostrara el numero de coincidencia, el comienzo y el fin. Compilemos y ejecutemos para ver su salida:
$ java RegexCoinc
Match number 1
start(): 0
end(): 3
Match number 2
start(): 4
end(): 7
Match number 3
start(): 8
end(): 11
Match number 4
start(): 19
end(): 22
$
Los metodos replaceFirst y replaceAll
RegexCoinc.java
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexCoinc
{
private static String REGEX = "perro";
private static String INPUT = "El perro dice miau. "
+ "Todos los perros dicen miau";
private static String REPLACE = "gato";
private static String TEMP;
public static void main( String args[])
{
System.out.println(INPUT);
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT);
TEMP = m.replaceFirst(REPLACE);
INPUT = m.replaceAll(REPLACE);
System.out.println(TEMP);
System.out.println(INPUT);
}
}
En este programa vamos a tener tres textos y uno vacio, en el primero va a ser el texto a buscar (REGEX), el segundo caso va a ser el texto de entrada (INPUT), el tercero va a ser el texto a reemplazar (REPLACE) y por ultimo uno vacio de estilo temporal (TEMP). Luego en el cuerpo del main(), primero mostraremos el texto de entrada. Despues compilaremos la expresion de busqueda, crearemos un objeto de tipo Matcher llamado m, donde usaremos el metodo matcher(). Lo siguiente sera usar a TEMP donde por medio de m le asignaremos la primer coincidencia de REGEX con REPLACE. Para luego modificar a INPUT reemplazando todas las expresiones regulares con el texto de REPLACE. En las ultimas dos lineas, primero mostraremos el cambio en TEMP y luego el cambio de INPUT. Si lo compilamos y ejecutamos obtendremos la siguiente salida:
$ java RegexCoinc
El perro dice miau. Todos los perros dicen miau
El gato dice miau. Todos los perros dicen miau
El gato dice miau. Todos los gatos dicen miau
$
Como pueden ver primero tenemos la variable INPUT sin modificacion, luego en TEMP (la segunda linea) se modifico unicamente la primera coincidencia y la ultima linea muestra el cambio de todas las coincidencias en INPUT.
En resumen, hoy hemos visto Expresiones regulares, desde las nociones basicas, las clases a utilizar, los modificadores, hemos visto los metodos para obtener los indices, posiciones de una coincidencia, metodos para reemplazarlos de distintas formas, los metodos de estudio y por ultimo los metodos para poder ver un error en estos casos. Espero les haya sido de utilidad y les dejo algunas de mis redes sociales para seguirme o recibir una notificacion cada vez que subo un nuevo post:


Donación
Es para mantenimento del sitio, gracias!
$1.50





