Referencias a grupos de captura en expresiones regulares y reemplazos

Escrito por el , actualizado el .
java planeta-codigo programacion
Enlace permanente Comentarios

Java

Las expresiones regulares definen un patrón que permite encontrar coincidencias en cadenas de caracteres, reemplazar coincidencias o validar que las cadenas de caracteres cumplen el patrón. Las expresiones regulares son potentes expresiones que resultan útiles en muchos casos pero son expresiones que pueden llegar a ser complejas cuyo uso se aprende con la experiencia. Una de las funcionalidades que poseen es hacer referencia a grupos de captura anteriores en la propia expresión regular o en la cadena de reemplazo.

Hacer referencia al grupo de captura en las cadenas de reemplazo es especialmente útil ya que sirve no solo para reemplazar coincidencias por cadenas previamente conocidas sino para transformar las coincidencias encontradas por otras expresiones. El caso de las cuentas de correo a continuación es un ejemplo práctico donde se aprecia este uso.

Supongamos que queremos corregir un texto en el que por error hay palabras repetidas de forma seguida y queremos eliminar esos duplicados de palabras. Por ejemplo, tenemos un texto como el siguiente en el algunas palabras como ipsum, eiusmod, fugiat, sint y proident están repetidas:

1
2
Lorem ipsum ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat fugiat nulla pariatur. Excepteur sint sint occaecat cupidatat non proident proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

lorem-ipsum.txt

La expresión regular para encontrar las coincidencias deberá para cada palabra comprobar si la siguiente es la misma. Cada palabra la incluimos en un grupo y posteriormente hacemos referencia a ese grupo con \1 para ver si la siguiente palabra es la misma. Con la siguiente expresión regular y código encontraremos las palabras repetidas una a continuación de la otra.

Para hacer referencia en los grupos de coincidencia en la cadena de reemplazo hay que usar un caracter $ y un número con la posición del grupo de reemplazo.

Un ejemplo más útil de los grupos de referencia en la cadena de reemplazo sería reemplazar en un texto plano las direcciones de correo electrónico por sus enlaces en HTML. Usando una expresión regular para encontrar las direcciones de correo electrónico y sustituirlas por los enlaces HTML haciendo uso de los grupos de captura y referencias a ellos.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package io.github.picodotdev.blogbitix.javaregexreferencegroups;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {

    public static void main(String[] args) {
        String text = "Lorem ipsum ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat fugiat nulla pariatur. Excepteur sint sint occaecat cupidatat non proident proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";

        System.out.println("Palabras duplicadas:");
        Pattern p = Pattern.compile("\\s([a-zA-Z]+)\\s\\1");
        Matcher m = p.matcher(text);
        while (m.find()) {
            System.out.printf("* %s%n", m.group(1));
        }

        System.out.println("");
        System.out.println("Texto sin palabras duplicadas:");
        System.out.println(text.replaceAll("\\s([a-zA-Z]+)\\s\\1", " $1"));

        System.out.println("");
        String emails = "pedro@gmail.com\njuan@gmail.com\nsonia@gmail.com";
        {
            String emailregexp = "((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\]))";
            System.out.println(emails.replaceAll(emailregexp, "<a href=\"$1\">$1</a>"));
        }

        System.out.println("");
        {
            String emailregexp = "(?<email>(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\]))";
            System.out.println(emails.replaceAll(emailregexp, "<a href=\"${email}\">${email}</a>"));
        }
    }
}
Main.java

La salida del ejemplo en la terminal es el siguiente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Palabras duplicadas:
* ipsum
* eiusmod
* fugiat
* sint
* proident

Texto sin palabras duplicadas:
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

<a href="pedro@gmail.com">pedro@gmail.com</a>
<a href="juan@gmail.com">juan@gmail.com</a>
<a href="sonia@gmail.com">sonia@gmail.com</a>

<a href="pedro@gmail.com">pedro@gmail.com</a>
<a href="juan@gmail.com">juan@gmail.com</a>
<a href="sonia@gmail.com">sonia@gmail.com</a>
system.out

A los grupos de captura se les puede dar un nombre y referenciarlos por él en vez de por un número identificador como en el de este ejemplo. A un grupo de captura se le da un nombre con la siguiente expresión (?<name>X) donde name es el nombre del grupo de captura de la expresión X. Posteriormente con la expresión ${name} se hace referencia al grupo de captura, también en la cadena de reemplazo.

En la documentación Javadoc de la clase Pattern está detallado el soporte en Java para usar expresiones regulares. Otra aplicación práctica de los grupos de captura es formatear con colores en la terminal una sentencia SQL o código fuente de un lenguaje.

Terminal

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando siguiente comando:
./gradlew run


Comparte el artículo: