test regular online net expressions ejemplos c# .net regex

c# - online - ¿Cuál es la diferencia entre "grupos" y "capturas" en expresiones regulares de.NET?



regex email c# (5)

De la documentation MSDN:

La verdadera utilidad de la propiedad Captures ocurre cuando un cuantificador se aplica a un grupo de captura, de modo que el grupo captura múltiples subcadenas en una única expresión regular. En este caso, el objeto Grupo contiene información sobre la última subcadena capturada, mientras que la propiedad Capturas contiene información sobre todas las subcadenas capturadas por el grupo. En el siguiente ejemplo, la expresión regular / b (/ w + / s *) +. coincide con una oración completa que termina en un punto. El grupo (/ w + / s *) + captura las palabras individuales en la colección. Como la colección de grupo contiene información solo sobre la última subcadena capturada, captura la última palabra de la oración, "oración". Sin embargo, cada palabra capturada por el grupo está disponible en la colección devuelta por la propiedad Capturas.

Estoy un poco confuso sobre cuál es la diferencia entre un "grupo" y una "captura" cuando se trata del lenguaje de expresiones regulares de .NET. Considere el siguiente código de C #:

MatchCollection matches = Regex.Matches("{Q}", @"^/{([A-Z])/}$");

Espero que esto resulte en una sola captura para la letra ''Q'', pero si MatchCollection las propiedades del MatchCollection devuelto, veo:

matches.Count: 1 matches[0].Value: {Q} matches[0].Captures.Count: 1 matches[0].Captures[0].Value: {Q} matches[0].Groups.Count: 2 matches[0].Groups[0].Value: {Q} matches[0].Groups[0].Captures.Count: 1 matches[0].Groups[0].Captures[0].Value: {Q} matches[0].Groups[1].Value: Q matches[0].Groups[1].Captures.Count: 1 matches[0].Groups[1].Captures[0].Value: Q

Qué está pasando aquí? Entiendo que también hay una captura para todo el partido, pero ¿cómo entran los grupos? ¿Y por qué no matches[0].Captures incluyen la captura de la letra "Q"?


Esto se puede explicar con un simple ejemplo (e imágenes).

Coincidencia a las 3:10pm con la expresión regular ((/d)+):((/d)+)(am|pm) , y usando el csharp interactivo Mono:

csharp> Regex.Match("3:10pm", @"((/d)+):((/d)+)(am|pm)"). > Groups.Cast<Group>(). > Zip(Enumerable.Range(0, int.MaxValue), (g, n) => "[" + n + "] " + g); { "[0] 3:10pm", "[1] 3", "[2] 3", "[3] 10", "[4] 0", "[5] pm" }

Entonces, ¿dónde está el 1?

Dado que hay múltiples dígitos que coinciden en el cuarto grupo, solo "conseguimos" el último partido si hacemos referencia al grupo (con un ToString() implícito ToString() , eso es). Para exponer las coincidencias intermedias, necesitamos profundizar y hacer referencia a la propiedad de Captures en el grupo en cuestión:

csharp> Regex.Match("3:10pm", @"((/d)+):((/d)+)(am|pm)"). > Groups.Cast<Group>(). > Skip(4).First().Captures.Cast<Capture>(). > Zip(Enumerable.Range(0, int.MaxValue), (c, n) => "["+n+"] " + c); { "[0] 1", "[1] 0" }

Cortesía de este artículo .


Imagine que tiene el siguiente texto de entrada dogcatcatcat y un patrón como dog(cat(catcat))

En este caso, tiene 3 grupos, el primero ( grupo principal ) corresponde al partido.

Coincidencia == dogcatcatcat y Group0 == dogcatcatcat

catcatcat == catcatcat

Group2 == catcat

Entonces, ¿de qué se trata?

Consideremos un pequeño ejemplo escrito en C # (.NET) usando la clase Regex .

int matchIndex = 0; int groupIndex = 0; int captureIndex = 0; foreach (Match match in Regex.Matches( "dogcatabcdefghidogcatkjlmnopqr", // input @"(dog(cat(...)(...)(...)))") // pattern ) { Console.Out.WriteLine($"match{matchIndex++} = {match}"); foreach (Group @group in match.Groups) { Console.Out.WriteLine($"/tgroup{groupIndex++} = {@group}"); foreach (Capture capture in @group.Captures) { Console.Out.WriteLine($"/t/tcapture{captureIndex++} = {capture}"); } captureIndex = 0; } groupIndex = 0; Console.Out.WriteLine(); }

Salida :

match0 = dogcatabcdefghi group0 = dogcatabcdefghi capture0 = dogcatabcdefghi group1 = dogcatabcdefghi capture0 = dogcatabcdefghi group2 = catabcdefghi capture0 = catabcdefghi group3 = abc capture0 = abc group4 = def capture0 = def group5 = ghi capture0 = ghi match1 = dogcatkjlmnopqr group0 = dogcatkjlmnopqr capture0 = dogcatkjlmnopqr group1 = dogcatkjlmnopqr capture0 = dogcatkjlmnopqr group2 = catkjlmnopqr capture0 = catkjlmnopqr group3 = kjl capture0 = kjl group4 = mno capture0 = mno group5 = pqr capture0 = pqr

Analicemos solo la primera coincidencia ( match0 ).

Como puede ver, hay tres grupos menores : group3 , group4 y group5

group3 = kjl capture0 = kjl group4 = mno capture0 = mno group5 = pqr capture0 = pqr

Esos grupos (3-5) se crearon debido al '' subpatrón '' (...)(...)(...) del patrón principal (dog(cat(...)(...)(...)))

El valor del group3 corresponde a su captura ( capture0 ). (Como en el caso de group4 y group5 ). Eso es porque no hay repetición grupal como (...){3} .

Bien, consideremos otro ejemplo donde hay una repetición grupal .

Si modificamos el patrón de expresión regular que se emparejará (para el código mostrado arriba) de (dog(cat(...)(...)(...))) a (dog(cat(...){3})) , notará que hay la siguiente repetición de grupo : (...){3} .

Ahora la salida ha cambiado:

match0 = dogcatabcdefghi group0 = dogcatabcdefghi capture0 = dogcatabcdefghi group1 = dogcatabcdefghi capture0 = dogcatabcdefghi group2 = catabcdefghi capture0 = catabcdefghi group3 = ghi capture0 = abc capture1 = def capture2 = ghi match1 = dogcatkjlmnopqr group0 = dogcatkjlmnopqr capture0 = dogcatkjlmnopqr group1 = dogcatkjlmnopqr capture0 = dogcatkjlmnopqr group2 = catkjlmnopqr capture0 = catkjlmnopqr group3 = pqr capture0 = kjl capture1 = mno capture2 = pqr

De nuevo, analicemos solo la primera coincidencia ( match0 ).

No hay más grupos menores group4 y group5 debido a (...){3} repetición ( {n} donde n> = 2 ) se han fusionado en un solo grupo group3 .

En este caso, el valor de group3 corresponde a su capture2 ( la última captura , en otras palabras).

Por lo tanto, si necesita las 3 capturas internas ( capture0 , capture1 , capture2 ), tendrá que capture2 por la colección de Captures del grupo.

La conclusión es: preste atención a la forma en que diseña los grupos de su patrón. Debería pensar por adelantado qué comportamiento causa la especificación del grupo, como (...)(...) , (...){2} o (.{3}){2} etc.

Esperemos que ayude a arrojar algo de luz sobre las diferencias entre Capturas , Grupos y Partidos también.


No serás el primero en ser confuso al respecto. Esto es lo que el famoso Jeffrey Friedl tiene que decir al respecto (páginas 437+):

Dependiendo de su punto de vista, agrega una nueva dimensión interesante a los resultados de los partidos, o agrega confusión e hinchazón.

Y más adelante:

La diferencia principal entre un objeto de grupo y un objeto de captura es que cada objeto de grupo contiene una colección de capturas que representan todas las coincidencias intermedias del grupo durante la coincidencia, así como el texto final que coincide con el grupo.

Y unas pocas páginas más tarde, esta es su conclusión:

Después de superar la documentación de .NET y comprender realmente qué es lo que estos objetos agregan, tengo sentimientos encontrados sobre ellos. Por un lado, es una innovación interesante [..] por otro lado, parece agregar una carga de eficiencia [..] de una funcionalidad que no se usará en la mayoría de los casos.

En otras palabras: son muy similares, pero de vez en cuando y, como sucede, encontrarás un uso para ellos. Antes de que cultives otra barba gris, incluso puedes encariñarte con las Capturas ...

Dado que ni lo anterior, ni lo que se dice en la otra publicación realmente parece responder a su pregunta, considere lo siguiente. Piensa en Captures como una especie de rastreador de historia. Cuando la expresión regular hace su coincidencia, recorre la cadena de izquierda a derecha (ignorando el retroceso por un momento) y cuando encuentra un paréntesis de captura coincidente, almacenará eso en $x (x es cualquier dígito), digamos $1 .

Los motores de expresiones regulares normales, cuando se repiten los paréntesis de captura, tirarán el $1 actual y lo reemplazarán con el nuevo valor. Not .NET, que mantendrá este historial y lo ubicará en Captures[0] .

Si cambiamos su expresión regular para que se vea de la siguiente manera:

MatchCollection matches = Regex.Matches("{Q}{R}{S}", @"(/{[A-Z]/})+");

observará que el primer Group tendrá una Captures (el primer grupo siempre será la coincidencia completa, es decir, igual a $0 ) y el segundo grupo tendrá {S} , es decir, solo el último grupo coincidente. Sin embargo, y aquí está el truco, si quieres encontrar las otras dos capturas, están en Captures , que contiene todas las capturas intermedias para {Q} {R} y {S} .

Si alguna vez se preguntó cómo podría obtener de la captura múltiple, que solo muestra la última coincidencia de las capturas individuales que están claramente allí en la cadena, debe usar Captures .

Una última palabra sobre su última pregunta: la coincidencia total siempre tiene una Captura total, no la mezcle con los Grupos individuales. Las capturas solo son interesantes dentro de los grupos .


Un grupo es lo que hemos asociado con grupos en expresiones regulares

"(a[zx](b?))" Applied to "axb" returns an array of 3 groups: group 0: axb, the entire match. group 1: axb, the first group matched. group 2: b, the second group matched.

excepto que estos son solo grupos "capturados". Los grupos que no capturan (usando la sintaxis ''(?:'') No están representados aquí.

"(a[zx](?:b?))" Applied to "axb" returns an array of 2 groups: group 0: axb, the entire match. group 1: axb, the first group matched.

Una captura también es lo que hemos asociado con ''grupos capturados''. Pero cuando el grupo se aplica con un cuantificador varias veces, solo la última coincidencia se mantiene como la coincidencia del grupo. La matriz de capturas almacena todas estas coincidencias.

"(a[zx]/s+)+" Applied to "ax az ax" returns an array of 2 captures of the second group. group 1, capture 0 "ax " group 1, capture 1 "az "

En cuanto a su última pregunta, antes de analizar esto, habría pensado que Captures sería una selección de las capturas ordenadas por el grupo al que pertenecen. Más bien es solo un alias para los grupos [0]. Capturas. Bastante inútil ..