Pregunta ¿Qué es un grupo que no captura? ¿Que es lo que hace?


Cómo ?: se usa y para qué sirve?


1320
2017-08-18 13:17


origen


Respuestas:


Déjame intentar explicar esto con un ejemplo.

Considera el siguiente texto:

https://stackoverflow.com/
https://stackoverflow.com/questions/tagged/regex

Ahora, si aplico la expresión regular a continuación ...

(https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?

... obtendría el siguiente resultado:

Match "https://stackoverflow.com/"
     Group 1: "http"
     Group 2: "stackoverflow.com"
     Group 3: "/"

Match "https://stackoverflow.com/questions/tagged/regex"
     Group 1: "http"
     Group 2: "stackoverflow.com"
     Group 3: "/questions/tagged/regex"

Pero no me importa el protocolo, solo quiero el host y la ruta de la URL. Entonces, cambio la expresión regular para incluir el grupo que no capturó (?:).

(?:https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?

Ahora, mi resultado se ve así:

Match "https://stackoverflow.com/"
     Group 1: "stackoverflow.com"
     Group 2: "/"

Match "https://stackoverflow.com/questions/tagged/regex"
     Group 1: "stackoverflow.com"
     Group 2: "/questions/tagged/regex"

¿Ver? El primer grupo no ha sido capturado. El analizador lo usa para hacer coincidir el texto, pero lo ignora más tarde, en el resultado final.


EDITAR:

Según lo solicitado, permítame intentar explicar los grupos también.

Bueno, los grupos sirven para muchos propósitos. Pueden ayudarlo a extraer la información exacta de una coincidencia más grande (que también se puede nombrar), le permiten volver a emparejar un grupo coincidente anterior y pueden usarse para sustituciones. Vamos a probar algunos ejemplos, ¿de acuerdo?

Ok, imagina que tienes algún tipo de XML o HTML (ten en cuenta que regex puede no ser la mejor herramienta para el trabajo, pero es bueno como un ejemplo). Desea analizar las etiquetas, por lo que podría hacer algo como esto (he agregado espacios para que sea más fácil de entender):

   \<(?<TAG>.+?)\> [^<]*? \</\k<TAG>\>
or
   \<(.+?)\> [^<]*? \</\1\>

La primera expresión regular tiene un grupo con nombre (TAG), mientras que la segunda usa un grupo común. Ambas expresiones regulares hacen lo mismo: usan el valor del primer grupo (el nombre de la etiqueta) para que coincida con la etiqueta de cierre. La diferencia es que el primero usa el nombre para que coincida con el valor, y el segundo usa el índice de grupo (que comienza en 1).

Probemos algunas sustituciones ahora. Considera el siguiente texto:

Lorem ipsum dolor sit amet consectetuer feugiat fames malesuada pretium egestas.

Ahora, usemos esta tonta expresión regular sobre ella:

\b(\S)(\S)(\S)(\S*)\b

Esta expresión regular coincide con las palabras con al menos 3 caracteres y utiliza grupos para separar las primeras tres letras. El resultado es esto:

Match "Lorem"
     Group 1: "L"
     Group 2: "o"
     Group 3: "r"
     Group 4: "em"
Match "ipsum"
     Group 1: "i"
     Group 2: "p"
     Group 3: "s"
     Group 4: "um"
...

Match "consectetuer"
     Group 1: "c"
     Group 2: "o"
     Group 3: "n"
     Group 4: "sectetuer"
...

Entonces, si aplicamos la cadena de sustitución ...

$1_$3$2_$4

... sobre él, estamos tratando de usar el primer grupo, agregar un guión bajo, usar el tercer grupo, luego el segundo grupo, agregar otro guión bajo y luego el cuarto grupo. La cadena resultante sería como la siguiente.

L_ro_em i_sp_um d_lo_or s_ti_ a_em_t c_no_sectetuer f_ue_giat f_ma_es m_la_esuada p_er_tium e_eg_stas.

También puede usar grupos nombrados para sustituciones, usando ${name}.

Para jugar con expresiones regulares, recomiendo http://regex101.com/, que ofrece una buena cantidad de detalles sobre cómo funciona la expresión regular; también ofrece algunos motores de expresiones regulares para elegir.


1828
2017-08-18 15:39



Puede usar grupos de captura para organizar y analizar una expresión. Un grupo no captor tiene el primer beneficio, pero no tiene la sobrecarga del segundo. Aún puede decir que un grupo que no captura es opcional, por ejemplo.

Supongamos que desea hacer coincidir el texto numérico, pero algunos números podrían escribirse como 1º, 2º, 3º, 4º, ... Si desea capturar la parte numérica, pero no el sufijo (opcional), puede usar un grupo que no captura. .

([0-9]+)(?:st|nd|rd|th)?

Eso coincidirá con los números en la forma 1, 2, 3 ... o en la forma 1, 2, 3, ... pero solo capturará la parte numérica.


135
2017-08-18 13:24



?: se usa cuando desea agrupar una expresión, pero no desea guardarla como una porción coincidente / capturada de la cadena.

Un ejemplo sería algo que coincida con una dirección IP:

/(?:\d{1,3}\.){3}\d{1,3}/

Tenga en cuenta que no me importa guardar los primeros 3 octetos, pero (?:...) la agrupación me permite acortar la expresión regular sin incurrir en la sobrecarga de capturar y almacenar una coincidencia.


87
2017-08-18 13:22



Hace que el grupo no capture, lo que significa que la subcadena emparejada por ese grupo no se incluirá en la lista de capturas. Un ejemplo en ruby ​​para ilustrar la diferencia:

"abc".match(/(.)(.)./).captures #=> ["a","b"]
"abc".match(/(?:.)(.)./).captures #=> ["b"]

27
2017-08-18 13:23



MOTIVACIÓN HISTÓRICA: La existencia de grupos no capturadores se puede explicar con el uso de paréntesis. Considere las expresiones (a | b) c y a | bc, debido a la prioridad de la concatenación sobre |, estas expresiones representan dos idiomas diferentes ({ac, bc} y {a, bc} respectivamente). Sin embargo, los paréntesis también se usan como un grupo coincidente (como se explica en las otras respuestas ...).

Cuando quiere tener paréntesis pero no captura la subexpresión, usa GRUPOS NO CAPTADORES. En el ejemplo, (?: A | b) c


13
2018-02-04 08:07



Grupos que capturar puedes usar más adelante en la expresión regular para que coincida O puede usarlos en la parte de reemplazo de la expresión regular. Haciendo una no capturar grupo simplemente exime ese grupo de ser utilizado por cualquiera de estas razones.

Los grupos que no capturan son geniales si intenta capturar muchas cosas diferentes y hay algunos grupos que no desea capturar.

Esa es básicamente la razón por la que existen. Mientras aprende sobre grupos, aprenda sobre Grupos atómicos, ellos hacen mucho! También hay grupos alternativos pero son un poco más complejos y no se usan tanto.

Ejemplo de uso posterior en la expresión regular (retroreferencia):

<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1>  [Encuentra una etiqueta xml (sin soporte ns)]

([A-Z][A-Z0-9]*) es un grupo de captura (en este caso es el nombre de etiqueta)

Más adelante en la expresión regular es \1 lo que significa que solo coincidirá con el mismo texto que estaba en el primer grupo (el ([A-Z][A-Z0-9]*) grupo) (en este caso, coincide con la etiqueta final).


12
2017-08-18 13:22



Déjame probar esto con un ejemplo:

Código Regex: - (?:animal)(?:=)(\w+)(,)\1\2

Cadena de búsqueda :-

Línea 1 - animal = gato, perro, gato, tigre, perro

Línea 2 - animal = gato, gato, perro, perro, tigre

Línea 3 - animal = perro, perro, gato, gato, tigre

(?:animal) -> Grupo no capturado 1

(?:=)-> Grupo 2 no capturado

(\w+)-> Grupo capturado 1

(,)-> Grupo capturado 2

\1 -> resultado del grupo 1 capturado, es decir, en la línea 1 es gato, en la línea 2 es gato, en la línea 3 es perro.

\2 -> resultado del grupo capturado 2, es decir, coma (,)

Entonces en este código dando \ 1 y \ 2 recordamos o repetimos el resultado del grupo capturado 1 y 2 respectivamente más adelante en el código.

Según el orden del código (?: Animal) debería ser el grupo 1 y (?: =) Debería ser el grupo 2 y continúa ..

pero al dar el?: hacemos que el grupo de coincidencia no sea capturado (que no cuenta en el grupo coincidente, por lo que el número de agrupación comienza desde el primer grupo capturado y no el no capturado), de modo que la repetición del resultado del emparejamiento -grupo (?: animal) no se puede llamar más tarde en el código.

Espero que esto explique el uso del grupo que no captura.

enter image description here


8
2018-01-19 11:36



Bueno, soy un desarrollador de JavaScript e intentaré explicar su significado relacionado con JavaScript.

Considere un escenario en el que desea hacer coincidir cat is animal cuando desee coincidir gato y animal y ambos deben tener una is entre ellos.

 // this will ignore "is" as that's is what we want
"cat is animal".match(/(cat)(?: is )(animal)/) ;
result ["cat is animal", "cat", "animal"]

 // using lookahead pattern it will match only "cat" we can
 // use lookahead but the problem is we can not give anything
 // at the back of lookahead pattern
"cat is animal".match(/cat(?= is animal)/) ;
result ["cat"]

 //so I gave another grouping parenthesis for animal
 // in lookahead pattern to match animal as well
"cat is animal".match(/(cat)(?= is (animal))/) ;
result ["cat", "cat", "animal"]

 // we got extra cat in above example so removing another grouping
"cat is animal".match(/cat(?= is (animal))/) ;
result ["cat", "animal"]

6
2018-03-01 09:43



En expresiones regulares complejas, es posible que surja la situación en la que desee utilizar una gran cantidad de grupos, algunos de los cuales están allí para la repetición y algunos de los cuales están ahí para proporcionar referencias. De forma predeterminada, el texto que coincide con cada grupo se carga en la matriz de referencia inversa. Donde tenemos muchos grupos y solo necesitamos poder hacer referencia a algunos de ellos desde la matriz de retroreferencia, podemos anular este comportamiento predeterminado para decirle a la expresión regular que ciertos grupos solo están ahí para el manejo de repeticiones y no necesitan ser capturados y almacenados en la matriz de referencia inversa.


5
2018-03-08 17:33



Una cosa interesante que encontré es el hecho de que puedes tener un grupo de captura dentro de un grupo que no captura. Echa un vistazo a la expresión regular a continuación para las URL web coincidentes:

var parse_url_regex = /^(?:([A-Za-z]+):)(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;

Cadena de URL de entrada:

var url = "http://www.ora.com:80/goodparts?q#fragment";

El primer grupo en mi expresión regular (?:([A-Za-z]+):) es un grupo no captor que coincide con el esquema de protocolo y colon : carácter, es decir http: pero cuando estaba corriendo por debajo del código, estaba viendo que el primer índice de la matriz devuelta contenía la cadena http cuando estaba pensando eso http y colon : ambos no serán informados ya que están dentro de un grupo que no captura.

console.debug(parse_url_regex.exec(url));

enter image description here

Pensé que si el primer grupo (?:([A-Za-z]+):) es un grupo que no captura, entonces por qué está regresando http cadena en la matriz de salida.

Entonces, si notas que hay un grupo anidado ([A-Za-z]+) dentro del grupo que no captura Ese grupo anidado ([A-Za-z]+) es un grupo de captura (que no tiene ?: al principio) en sí mismo dentro de un grupo no capturante (?:([A-Za-z]+):). Es por eso que el texto http todavía se captura, pero el colon : El carácter que está dentro del grupo que no captura pero que está fuera del grupo de captura no se informa en la matriz de salida.


4
2017-07-15 03:13