Java regex capturando índices de grupos

113

Tengo la siguiente linea,

typeName="ABC:xxxxx;";

Necesito a buscar la palabra ABC,

Escribí el siguiente fragmento de código,

Pattern pattern4=Pattern.compile("(.*):");
matcher=pattern4.matcher(typeName);

String nameStr="";
if(matcher.find())
{
    nameStr=matcher.group(1);

}

Entonces si pongo group(0)lo consigo ABC:pero si lo pongo group(1)es ABC, entonces quiero saber

  1. ¿Qué significa esto 0y 1? Será mejor si alguien me puede explicar con buenos ejemplos.

  2. El patrón de expresiones regulares contiene un :, entonces, ¿por qué el group(1)resultado lo omite? ¿El grupo 1 detecta todas las palabras entre paréntesis?

  3. Entonces, si pongo dos paréntesis más como,: \\s*(\d*)(.*)entonces, ¿habrá dos grupos? group(1)devolverá la (\d*)pieza y group(2)devolverá la (.*)pieza?

El fragmento de código se proporcionó con el propósito de aclarar mis confusiones. No es el código con el que estoy tratando. El código proporcionado anteriormente se puede hacer String.split()de una manera mucho más fácil.

P basak
fuente

Respuestas:

182

Capturar y agrupar

El grupo de captura (pattern) crea un grupo que tiene propiedad de captura .

Uno relacionado que a menudo puede ver (y usar) es (?:pattern), que crea un grupo sin capturar la propiedad, de ahí el nombre de grupo no capturador .

Por lo general, se utiliza un grupo cuando se necesita repetir una secuencia de patrones, por ejemplo (\.\w+)+, o para especificar dónde debe tener efecto la alternancia, por ejemplo ^(0*1|1*0)$( ^, entonces 0*1o 1*0, luego $) versus ^0*1|1*0$( ^0*1o 1*0$).

Un grupo de captura, además de agrupar, también registrará el texto que coincide con el patrón dentro del grupo de captura (pattern). Usando su ejemplo (.*):, .*partidos ABCy :partidos :, y dado que .*está dentro de captura de grupo (.*), el texto ABCse registra para el grupo de captura 1.

Número de grupo

El patrón completo se define como el grupo número 0.

Cualquier grupo de captura en el patrón comienza a indexar desde 1. Los índices se definen por el orden de los paréntesis de apertura de los grupos de captura . Como ejemplo, aquí están los 5 grupos de captura en el siguiente patrón:

(group)(?:non-capturing-group)(g(?:ro|u)p( (nested)inside)(another)group)(?=assertion)
|     |                       |          | |      |      ||       |     |
1-----1                       |          | 4------4      |5-------5     |
                              |          3---------------3              |
                              2-----------------------------------------2

Los números de grupo se utilizan en referencia \ninversa en patrón y $nen cadena de reemplazo.

En otros sabores de expresiones regulares (PCRE, Perl), también se pueden usar en llamadas a subrutinas .

Puede acceder al texto que coincide con cierto grupo con Matcher.group(int group). Los números de grupo se pueden identificar con la regla indicada anteriormente.

En algunos tipos de expresiones regulares (PCRE, Perl), hay una función de reinicio de rama que le permite usar el mismo número para capturar grupos en diferentes ramas de alternancia .

Nombre del grupo

Desde Java 7, puede definir un grupo de captura con nombre (?<name>pattern) y puede acceder al contenido que coincide con Matcher.group(String name). La expresión regular es más larga, pero el código es más significativo, ya que indica lo que está intentando hacer coincidir o extraer con la expresión regular.

Los nombres de los grupos se utilizan como referencia \k<name>inversa en el patrón y ${name}en la cadena de reemplazo.

Los grupos de captura con nombre todavía están numerados con el mismo esquema de numeración, por lo que también se puede acceder a ellos a través de Matcher.group(int group).

Internamente, la implementación de Java simplemente se asigna desde el nombre al número de grupo. Por lo tanto, no puede utilizar el mismo nombre para 2 grupos de captura diferentes.

nhahtdh
fuente
1
¡GUAUU! Gracias @nhahtdh por explicar los grupos que no capturan cómo funciona el orden de los grupos de anidación. Estaba perplejo sobre cómo funcionaban los números de grupo hasta que finalmente leí tu explicación. ¡Muchas gracias!
MMeah
92

Para el resto de nosotros

Aquí hay un ejemplo simple y claro de cómo funciona esto.

Regex: ([a-zA-Z0-9]+)([\s]+)([a-zA-Z ]+)([\s]+)([0-9]+)

Cuerda: "!* UserName10 John Smith 01123 *!"

group(0): UserName10 John Smith 01123
group(1): UserName10
group(2):  
group(3): John Smith
group(4):  
group(5): 01123

Como puede ver, he creado CINCO grupos, cada uno entre paréntesis.

Incluí el! * Y *! a cada lado para que quede más claro. Tenga en cuenta que ninguno de esos caracteres está en la expresión regular y, por lo tanto, no aparecerá en los resultados. El grupo (0) simplemente le da la cadena completa coincidente (todos mis criterios de búsqueda en una sola línea). El grupo 1 se detiene justo antes del primer espacio porque el carácter de espacio no se incluyó en los criterios de búsqueda. Los grupos 2 y 4 son simplemente el espacio en blanco, que en este caso es literalmente un carácter de espacio, pero también podría ser una pestaña o un salto de línea, etc. El grupo 3 incluye el espacio porque lo puse en los criterios de búsqueda ... etc.

Espero que esto tenga sentido.

Michael Sims
fuente
1
ejemplo perfecto que es fácil de entender para principiantes. Tengo una duda, ¿es esto lo mismo que la agrupación reg ex en Python? o si no hay alguna diferencia? Soy nuevo en reg ex, por eso estoy un poco confundido en ambos idiomas.
Mani
1
Esta no es una expresión regular de Java válida: las barras invertidas deben duplicarse.
Nicolas Raoul
1
@NicolasRaoul: la barra invertida doble se debe a la sintaxis de escape en el literal de cadena. La sintaxis de la expresión regular real (es decir, si imprime la cadena que contiene la expresión regular en la consola) no requiere doble barra invertida.
nhahtdh
@NicolasRaoul Si tuviera que copiar y pegar mi cadena de expresiones regulares en el código java real utilizando un IDE competente, el IDE formatearía correctamente las barras de escape según sea necesario. Pero mi Regex es técnica y sintácticamente correcta y tiene el propósito principal, que es demostrar la asociación entre el código de expresiones regulares y los resultados obtenidos (usando un ejemplo muy específico) ... aclarar un poco ... ☺
Michael Sims
44

Los paréntesis ()se utilizan para permitir la agrupación de frases de expresiones regulares.

El group(1)contiene la cadena que está entre paréntesis, (.*)así que .*en este caso

Y group(0)contiene una cadena completa a juego.

Si tuviera más grupos (leer (...)), se colocarían en grupos con los siguientes índices (2, 3, etc.).

Michal Borek
fuente
2
Entonces, ¿tengo razón en que agregar paréntesis es en realidad para crear grupos?
P basak
3
Sí, podemos decir eso.
Michal Borek