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

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

Déjame intentar explicar esto con un ejemplo.

Considera el siguiente texto:

 http://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 "http://stackoverflow.com/" Group 1: "http" Group 2: "stackoverflow.com" Group 3: "/" Match "https://stackoverflow.com/questions/tagged/regex" Group 1: "https" 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 captura (?:) .

 (?: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, imagine que tiene algún tipo de XML o HTML (tenga en cuenta que regex puede no ser la mejor herramienta para el trabajo , pero es bueno como ejemplo). Desea analizar las tags, por lo que podría hacer algo como esto (he agregado espacios para que sea más fácil de entender):

  \<(?.+?)\> [^<]*? \\> or \<(.+?)\> [^<]*? \ 

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 regexes, 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.

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.

?: 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.

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"] 

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

Los grupos que te capturan pueden usar más adelante en la expresión regular para que coincida O puedes usarlos en la parte de reemplazo de la expresión regular. Crear un grupo que no captura simplemente exime a ese grupo de ser utilizado por alguna 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 aprendes sobre grupos, aprende 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):

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

([AZ][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 que significa que solo coincidirá con el mismo texto que estaba en el primer grupo (el grupo ([AZ][A-Z0-9]*) ) (en este caso coincide con la etiqueta de finalización) )

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 capturado 1 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

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

Considera un escenario en el que quieras unir el cat is animal cuando quieras un gato y un animal, y ambos deben tener una a en medio de 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"] 

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.

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 dos puntos : carácter, es decir, http: pero cuando corría por debajo del código, estaba viendo el primer índice de la matriz devuelta contenía la cadena http cuando pensaba que http y colon : ambos no se informarán 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á devolviendo la cadena http en la matriz de salida.

Entonces, si observa que hay un grupo nested ([A-Za-z]+) dentro del grupo que no captura. Ese grupo nested ([A-Za-z]+) es un grupo de captura (que no tiene ?: Al principio) en sí mismo dentro de un grupo que no captura (?:([A-Za-z]+):) . Es por eso que el texto http sigue siendo capturado pero el carácter de dos puntos que está dentro del grupo que no captura pero que está fuera del grupo de captura no se informa en la matriz de salida.

tl; dr grupos que no capturan, como su nombre indica son las partes de la expresión regular que no desea que se incluyan en la coincidencia y ?: es una forma de definir que un grupo no se está capturando.

Supongamos que tiene una dirección de correo electrónico example@example.com . La siguiente expresión regular creará dos grupos , la parte id y la parte @ example.com. (\p{Alpha}*[az])(@example.com) . Por simplicidad, estamos extrayendo todo el nombre de dominio, incluido el carácter @ .

Ahora digamos que solo necesita la parte de identificación de la dirección. Lo que quiere hacer es tomar el primer grupo del resultado del partido, rodeado por () en la expresión regular y la forma de hacerlo es usar la syntax del grupo que no captura, es decir ?: . Entonces, la expresión regular (\p{Alpha}*[az])(?:@example.com) devolverá solo la parte de identificación del correo electrónico.

No puedo comentar las principales respuestas para decir esto: me gustaría agregar un punto explícito que solo está implícito en las respuestas principales:

El grupo que no captura (?...) no elimina ningún carácter de la coincidencia completa original, solo reorganiza la expresión regular visualmente para el progtwigdor.

Para acceder a una parte específica de la expresión regular sin caracteres externos definidos, siempre deberá usar .group()

Creo que le daría la respuesta. No use variables de captura sin verificar que la coincidencia haya tenido éxito.

Las variables de captura, $ 1, etc., no son válidas a menos que la coincidencia sea exitosa, y tampoco se borran.

 #!/usr/bin/perl use warnings; use strict; $_ = "bronto saurus burger"; if (/(?:bronto)? saurus (steak|burger)/) { print "Fred wants a $1"; } else { print "Fred dont wants a $1 $2"; } 

En el ejemplo anterior, para evitar la captura de bronto en $ 1, se usa (? :). Si el patrón se corresponde, entonces $ 1 se captura como el siguiente patrón agrupado. Por lo tanto, el resultado será el siguiente:

 Fred wants a burger 

Es útil si no desea que se guarden las coincidencias.

Abra su Google Chrome devTools y luego la pestaña Consola: y escriba esto:

 "Peace".match(/(\w)(\w)(\w)/) 

Ejecútalo y verás:

 ["Pea", "P", "e", "a", index: 0, input: "Peace", groups: undefined] 

El motor JavaScript RegExp captura tres grupos, los elementos con índices 1,2,3. Ahora usa marcas que no sean de captura para ver el resultado.

 "Peace".match(/(?:\w)(\w)(\w)/) 

El resultado es:

 ["Pea", "e", "a", index: 0, input: "Peace", groups: undefined] 

Esto es obvio lo que es un grupo que no captura.

    Intereting Posts