2010-02-11 10 views
11

Así que si escribo una expresión regular son coincidencias, puedo obtener la coincidencia o puedo acceder a sus grupos. Esto parece contrario a la intuición ya que los grupos se definen en la expresión con llaves "(" y ")". Parece que no solo es incorrecto sino redundante. ¿Alguien sabe por qué?En la expresión regular de C#, ¿por qué aparece la coincidencia inicial en los grupos?

Regex quickCheck = new Regex(@"(\D+)\d+"); 
string source = "abc123"; 

m.Value  //Equals source 
m.Groups.Count //Equals 2 
m.Groups[0]) //Equals source 
m.Groups[1]) //Equals "abc" 
+0

Mi primera respuesta [ahora eliminada] perdió un poco el sentido de su pregunta, por favor vea mi reemplazo, que da un ejemplo de dónde se muestra que este comportamiento tiene sentido (espero :)) –

Respuesta

4

Estoy de acuerdo - que es un poco extraño, sin embargo, piensa que hay buenas razones para eso.

A Regex Match es en sí mismo un Group, que a su vez es un Capture.

Pero Match.Value (o Capture.Value como lo es en realidad) solo es válido cuando hay una coincidencia presente en la cadena: si coincide varias instancias de un patrón, por definición no puede devolver todo. En efecto, la propiedad Value en el partido es una conveniencia para cuando solo hay partido.

Pero para aclarar donde este comportamiento de pasar todo el partido en Groups[0] tiene sentido - Considere este ejemplo (artificial) de un unminifier código ingenua:

[TestMethod] 
public void UnMinifyExample() 
{ 
    string toUnMinify = "{int somevalue = 0; /*init the value*/} /* end */"; 
    string result = Regex.Replace(toUnMinify, @"(;|})\s*(/\*[^*]*?\*/)?\s*", "$0\n"); 
    Assert.AreEqual("{int somevalue = 0; /*init the value*/\n} /* end */\n", result); 
} 

El partido expresión regular preservará/* */comentarios el final de una declaración, colocando una nueva línea después, pero funciona para cualquiera; o} terminaciones de línea.

bien - puede que se pregunte por qué te molesta hacer esto con una expresión regular - pero el humor me :)

Si Groups[0] generada por los partidos de esta expresión regular no era toda la captura - a continuación, un solo guardia reemplazar no sería posible - y su pregunta probablemente sería preguntar por qué no se el partido completo se pone en Groups[0] en lugar de al revés!

0

No creo que realmente haya una respuesta que no sea la persona que escribió esto que eligió como un detalle de implementación. Siempre que recuerde que el primer grupo siempre será igual a la cadena de origen, debería estar bien :-)

1

No estoy seguro por qué, pero si usa grupos con nombre, puede configurar la opción RegExOptions.ExplicitCapture y no debe incluir el fuente como primer grupo.

+0

Cambios 'ExplicitCapture' solamente el comportamiento de paréntesis en el patrón de expresión regular, el grupo 0 todavía contiene la coincidencia completa. –

0

Puede ser redundante, pero tiene algunas buenas propiedades.

Por ejemplo, significa que los grupos de captura funcionan del mismo modo que otros motores regex: el primer grupo de captura corresponde a "1", y así sucesivamente.

+0

Eso se siente mal, como matrices en VB. Tanto pensar en CS está basado en 0 que se trata de una segunda naturaleza. – QueueHammer

1

más probable para que pueda utilizar "$ 0" para representar al partido en una expresión de sustitución, y "$ 1" para el primer partido del grupo, etc.

0

Las referencias traseras se basan en una sola base, p., \1 o $1 es la primera subexpresión entre paréntesis, y así sucesivamente. Según lo establecido, uno se asigna al otro sin pensarlo.

También hay que resaltar: m.Groups["0"] le da toda la subcadena coincidente, así que asegúrese de saltar "0" si está interactuando sobre regex.GetGroupNames().

4

La documentación para Match dice que el primer grupo siempre es la coincidencia completa, por lo que no es un detalle de implementación.

2

Es histórico es todo. En Perl 5, los contenidos de los grupos de captura se almacenan en las variables especiales $1, $2, etc., pero C#, Java y otros, en su lugar, los almacenan en una matriz (o estructura similar a una matriz). Para preservar la compatibilidad con la convención de nomenclatura de Perl (que ha sido copiada por varios otros idiomas), el primer grupo se almacena en el elemento número uno, el segundo en el elemento dos, etc. Eso deja el elemento cero libre, entonces ¿por qué no almacenar el partido completo allí? ?

FYI, Perl 6 ha adoptado una nueva convención, en la que el primer grupo de captura se numera como cero en lugar de uno. Estoy seguro de que no fue hecho solo para enojarnos. ;)

Cuestiones relacionadas