Expresiones regulares en Java

Hay que tener en cuenta que usar expresiones regulares permite hacer búsquedas muy complejas, pero a cambio de un coste: la bajada de rendimiento en la velocidad de procesado. Una bajada no muy grande, pero que si se realiza muchas veces puede llegar a tener un coste muy alto, por lo que hay que evaluar en cada momento si es conveniente utilizar una expresión regular o recurrir a otras opciones como la función indexOf(String, int) de la clase String.

Para trabajar con expresiones regulares en Java se utiliza el paquete java.util.regex que está formado por dos clases, la clase Matcher y la clase Pattern, y una excepción PatternSyntaxException. La clase Pattern permite definir el patrón de búsqueda mediante el método compile(String).


Pattern p = Pattern.compile(“Java”);
// Define un patrón para buscar la palabra Java

A este método también se le pueden pasar una serie de flags, o indicadores, que permite modificar el patrón de búsqueda:

  • Pattern.CANON_EQ — Activa equivalencia canónica.
  • Pattern.CASE_INSENSITIVE — No diferencia entre mayúsculas y minúsculas.
  • Pattern.COMMENTS — Permite espacios en blanco y comentarios en el patrón.
  • Pattern.DOTALL — Activa el modo dotall. Si se aplica este modificador, unmeta-carácter punto en el patrón coincide con todos loscaracteres, incluyendo nuevas líneas. Sin él, las nuevaslíneas son excluidas.
  • Pattern.LITERAL — Activa el parseo literal del patrón.
  • Pattern.MULTILINE — Activa el modo multilinea.
  • Pattern.UNICODE_CASE — Activa el modo de comparación Unicode.
  • Pattern.UNIX_LINES — Activa el modo de líneas de Unix.

Pattern p = Pattern.compile(“Java”, Pattern.CASE_INSENSITIVE);
// Define un patrón para buscar la palabra Java ignorando mayúsculas y minúsculas

La clase Matcher es la que realiza las búsquedas dentro de un texto a partir de un patrón. Para crear un objeto de tipo Matcher se utiliza el método matcher(String) de la clase Pattern.


Matcher m = p.matcher(“Cadena en la que buscar el patrón especificado”);


Mediante el método find() se realizan las búsquedas dentro del texto. Cada vez que se ejecuta este método desplaza el cursor de búsqueda automáticamente por lo que con hacer un bucle ya se recorrería la cadena buscandolas coincidencias.

Una búsqueda:


if (m.find()) {
 System.out.println(matcher.group());
}

Varias búsquedas:


while (m.find()) {
 System.out.println(matcher.group());
}

En la clase Matcher cabe destacar también los métodos start() y end() que devuelven la posición del primer carácter de la ocurrencia y la posición del último carácter de la ocurrencia dentro del texto.

Grupos

Los grupos permiten extraer partes de una ocurrencia. Cada vez que se encierra una parte de la expresión regular

entre paréntesis se define un grupo.

Para obtener estos grupos se utiliza el método group() de la clase Matcher.


Pattern p = Pattern.compile(“<a href=’(.+?)’>(.+?)</a>”);
Matcher m =p.matcher(“<a href=’http://www.google.es’>Google</a>”);
System.out.println(m.group()); // <a href=’http://www.google.es’>Google</a>
System.out.println(m.group(1)); // http://www.google.es
System.out.println(m.group(2)); // Google

El método group() sin ningún parámetro develve toda la ocurrencia y el método group(int) devuelve sólo el grupo que se le indica empezando su numeración en 1. Ejecutar group(0) es lo mismo que ejecutar group().

Una gran ventaja de las expresiones regulares viene de la utilización de grupos ya que se pueden obtener muchísimos datos con un sólo patrón de búsqueda.

Un ejemplo sencillo sería obtener todos los enlaces que hay en la página principal de Google

try {
  URL url = new URL("http://www.google.es");
  URLConnection urlConn = url.openConnection();
  urlConn.setReadTimeout(60000);
  urlConn.setConnectTimeout(60000);
  Charset charset = Charset.forName("utf-8");
  BufferedReader br = new BufferedReader(new InputStreamReader(urlConn.getInputStream(), charset));
  String line = br.readLine();
  StringBuffer response = new StringBuffer();
  while (line != null) {
   response = response.append(line);
   line = br.readLine();
  }
  String pattern = "href=\"http://([^\"]+).+?>(.+?)</a>";
  Matcher matcher = Pattern.compile(pattern).matcher(response.toString());
  while (matcher.find()) {
   System.out.println("Nombre: " + matcher.group(2) + " | Enlace: " + matcher.group(1));
  }
 } catch(Exception e) {
  e.printStackTrace();
 }

Reemplazos

Para mi, esta es una de las grandes ventajas y gran potencia que te dan las expresiones regulares. El reemplazo con expresiones regulares es muy rápido y eficiente.

Primero vamos a crear una función que realiza un reemplazo de una cadena en un texto con expresiones regulares.


public StringBuffer replace (StringBuffer string, String pattern, String replacement) {
 StringBuffer auxStringBuffer = new StringBuffer();
 Matcher matcher = Pattern.compile(pattern).matcher(string);
 while (matcher.find()) {
  matcher.appendReplacement(auxStringBuffer, replacement);
 }
 matcher.appendTail(auxStringBuffer);
 return auxStringBuffer;
}

Donde String es la cadena donde se va a buscar el texto, pattern es el texto a buscar y replacement el texto por el que se va a sustituir. La eficiencia y la velocidad de esta función es inmensa. Permite sustituir cualquier cadena que cumpla con un patrón por otra. Por ejemplo, si quisiéramos sustituir todos los enlaces de la página principal de Google por un enlace a este blog, bastaría con llamar a la anterior función con


replaceString(response, pattern, "href=\"https://mejorenjava.wordpress.com\">Mejor en Java</a>")

Las expresiones regulares nos dan infinitos dolores de cabeza, pero una vez dominadas nos dan infinitas posibilidades. Por mi experiencia y las pruebas que he realizado las utilizo mucho, pero como ya he dicho antes, hay que evaluar siempre si merece la pena o no. He llegado a contabilizar pérdidas de segundos en determinadas operaciones repetitivas, pero también he mejorado procesos de forma increíble implementando su uso.

Anuncios
    • Fernando Reich
    • 12/09/11

    Escribo en este foro para pedir ayuda en un script Java que me permita resolver el siguinete problema de manejo de strings:

    Variable [texto]

    Si el string: [href=”http://en.wikipedia.org/wiki/”] existe en la variable [texto] y si [href=”http://en.wikipedia.org/wiki/] + los 5 caracteres siguientes es diferente a [href=”http://en.wikipedia.org/wiki/File]

    Entonces: Remplaza todo lo que esta a la derecha de [href=”] hasta [“] por [#]

    Si no: No hacer nada.

    El script tiene que hacer eso hasta que recorra toda la variable [texto].

    Saludos y gracias de ante mano por la buena voluntad

      • dieghada
      • 13/09/11

      Si no te he entendido mal, lo que buscas es algo así

      public String replaceLink(String string) {
      		
       String text = string;
       Matcher matcher = Pattern.compile("http://en.wikipedia.org/wiki/(File)* ").matcher(text) ;
      		
       if (matcher.find()) 
        text = matcher.replaceAll("#");
      		
       return text;
      }
      

      Un saludo

    • Luis
    • 17/08/12

    Quiero preguntarle si conoce alguna expresión regular que me permita buscar en un archivo con estructura XML.

    xxxxxxx
    bbbbbbbbb

    Por ejemplo, buscar una palabra dentro de categoría pero que lo que muestre sea el texto del titulo que corresponde

    Pero usando expresiones regulares.

    • Angélica
    • 16/10/12

    Que tiene menos coste y más rendimiento, llamar a Pattern.CASE_SENSITIVE o llamar utilizar dos patrones distintos para mayúsculas y minúsculas.

    Un saludo.

  1. No trackbacks yet.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s