Grupos de captura de expresiones regulares de Java

Resuelto Xivilai asked hace 11 años • 5 respuestas

Estoy tratando de entender este bloque de código. En el primero, ¿qué es lo que buscamos en la expresión?

Tengo entendido que es cualquier carácter (0 o más veces *) seguido de cualquier número entre 0 y 9 (una o más veces +) seguido de cualquier carácter (0 o más veces *).

Cuando esto se ejecuta el resultado es:

Found value: This order was placed for QT3000! OK?
Found value: This order was placed for QT300
Found value: 0

¿Alguien podría repasar esto conmigo?

¿Cuál es la ventaja de utilizar grupos de captura?

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

public class RegexTut3 {

    public static void main(String args[]) {
        String line = "This order was placed for QT3000! OK?"; 
        String pattern = "(.*)(\\d+)(.*)";

        // Create a Pattern object
        Pattern r = Pattern.compile(pattern);

        // Now create matcher object.
        Matcher m = r.matcher(line);

        if (m.find()) {
            System.out.println("Found value: " + m.group(0));
            System.out.println("Found value: " + m.group(1));
            System.out.println("Found value: " + m.group(2));
        } else {
            System.out.println("NO MATCH");
        }
    }

}
Xivilai avatar Jul 31 '13 18:07 Xivilai
Aceptado

El problema que tienes es con el tipo de cuantificador. Estás usando un cuantificador codicioso en tu primer grupo (índice 1 - índice 0 representa el todo Pattern), lo que significa que coincidirá tanto como pueda (y como es cualquier carácter, coincidirá con tantos caracteres como haya para cumplir la condición para los siguientes grupos).

En resumen, su primer grupo .*coincide con cualquier cosa siempre que el siguiente grupo \\d+pueda coincidir con algo (en este caso, el último dígito).

Según el tercer grupo, coincidirá con cualquier cosa después del último dígito.

Si lo cambia a un cuantificador reacio en su primer grupo, obtendrá el resultado que supongo que esperaba, es decir, la parte 3000 .

Tenga en cuenta el signo de interrogación en el primer grupo.

String line = "This order was placed for QT3000! OK?";
Pattern pattern = Pattern.compile("(.*?)(\\d+)(.*)");
Matcher matcher = pattern.matcher(line);
while (matcher.find()) {
    System.out.println("group 1: " + matcher.group(1));
    System.out.println("group 2: " + matcher.group(2));
    System.out.println("group 3: " + matcher.group(3));
}

Producción:

group 1: This order was placed for QT
group 2: 3000
group 3: ! OK?

Más información sobre Java Pattern aquí .

Finalmente, los grupos de captura están delimitados por corchetes y proporcionan una forma muy útil de utilizar referencias anteriores (entre otras cosas), una vez que Patterncoincida con la entrada.

En Java 6 solo se puede hacer referencia a los grupos por su orden (tenga cuidado con los grupos anidados y la sutileza del ordenamiento).

En Java 7 es mucho más fácil, ya que puedes usar grupos con nombre.

Mena avatar Jul 31 '2013 11:07 Mena

Esto está totalmente bien.

  1. El primer grupo ( m.group(0)) siempre captura toda el área cubierta por su expresión regular . En este caso, es toda la cadena.
  2. Las expresiones regulares son codiciosas por defecto, lo que significa que el primer grupo captura tanto como sea posible sin violar la expresión regular. ( La (.*)(\\d+)primera parte de su expresión regular) cubre el ...QT300int del primer grupo y el 0del segundo.
  3. Puedes solucionar este problema rápidamente haciendo que el primer grupo no sea codicioso: cámbialo (.*)a (.*?).

Para obtener más información sobre codiciosos y perezosos, consulte este sitio.

f1sh avatar Jul 31 '2013 11:07 f1sh

Su comprensión es correcta. Sin embargo, si recorremos:

  • (.*)se tragará toda la cuerda;
  • necesitará devolver caracteres para que (\\d+)quede satisfecho (razón por la cual 0se captura y no 3000);
  • el último (.*)capturará al resto.

Sin embargo, no estoy seguro de cuál era la intención original del autor.

fge avatar Jul 31 '2013 11:07 fge