2010-08-20 20 views
5

En .NET, regex no está organizando capturas como era de esperar. (No voy a llamar esto un error, porque obviamente alguien lo intentó. Sin embargo, no es cómo esperaba que funcionara ni lo encuentro útil.).NET regex no captura en el orden esperado

Esta expresión regular es para ingredientes de recetas (simplificado para el bien de ejemplo):

(?<measurement>   # begin group 
    \s*      # optional beginning space or group separator 
    (
    (?<integer>\d+)|  # integer 
    (
     (?<numtor>\d+)  # numerator 
    /
     (?<dentor>[1-9]\d*) # denominator. 0 not allowed 
    ) 
) 
    \s(?<unit>[a-zA-Z]+) 
)+      # end group. can have multiple 

Mi cadena: 3 tbsp 1/2 tsp

grupos resultantes y captura:

[medida] [0] = 3 cucharadas
[medida] [] = 1/2 cucharadita
[número entero] [0] = 3
[numtor] [] = 1
[Dentor] [] = 2
[unidad] [0] = cucharada
[unidad] [1 ] = cucharadita

Aviso cómo a pesar de 1/2 tsp está en la segunda captura, sus partes están en [0] ya que estos lugares eran previousl y no usado.

¿Hay alguna forma de que todas las partes tengan índices útiles predecibles sin tener que volver a ejecutar cada grupo a través de la expresión regular de nuevo?

Respuesta

1

¿Hay alguna manera de obtener todas las piezas tener índices útiles predecibles sin tener que volver a ejecutar cada grupo a través de la expresión regular de nuevo?

No con capturas.Y si se va a realizar varias coincidencias de todos modos, le sugiero que quita el + y combinar cada componente de la medición por separado, así:

string s = @"3 tbsp 1/2 tsp"; 

    Regex r = new Regex(@"\G\s* # anchor to end of previous match 
    (?<measurement>   # begin group 
     (
     (?<integer>\d+)  # integer 
     | 
     (
      (?<numtor>\d+)  # numerator 
     /
      (?<dentor>[1-9]\d*) # denominator. 0 not allowed 
     ) 
    ) 
     \s+(?<unit>[a-zA-Z]+) 
    )       # end group. 
    ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture); 

    foreach (Match m in r.Matches(s)) 
    { 
    for (int i = 1; i < m.Groups.Count; i++) 
    { 
     Group g = m.Groups[i]; 
     if (g.Success) 
     { 
     Console.WriteLine("[{0}] = {1}", r.GroupNameFromNumber(i), g.Value); 
     } 
    } 
    Console.WriteLine(""); 
    } 

de salida:

[measurement] = 3 tbsp 
[integer] = 3 
[unit] = tbsp 

[measurement] = 1/2 tsp 
[numtor] = 1 
[dentor] = 2 
[unit] = tsp 

El \G en el el principio garantiza que las coincidencias solo se produzcan en el punto donde finalizó la partida anterior (o al comienzo de la entrada si este es el primer intento de coincidencia). También puede guardar la posición final del partido entre llamadas, luego usar el método Matches de dos argumentos para reanudar el análisis en ese mismo punto (como si realmente fuera el comienzo de la entrada).

1

Parece que probablemente necesite recorrer la entrada, haciendo coincidir una medición a la vez. Entonces tendría acceso predecible a las partes de esa medición, durante la iteración del ciclo para esa medición.

-1

Tener un vistazo a esto .... aquí hay un par de sugerencias que podrían ayudar a mejorar la expresión regular

(?<measurement>   # begin group 
    \s*      # optional beginning space or group separator 
    (
    (?<integer>\d+)\.?| # integer 
    (
     (?<numtor>\d+)  # numerator 
    /
     (?<dentor>[1-9]\d*) # denominator. 0 not allowed 
    ) 
) 
    \s(?<unit>[a-zA-Z]+) 
)+      # end group. can have multiple 
  • la expresión regular está a la espera de un espacio en el inicio .... después de la etiqueta de medición ....
  • (?<integer>\d+) me gustaría probar \s? en lugar de \. para capturar el espacio en blanco ya que es escapar de la parada completa y estaría esperando un punto final a aparecer en algún lugar ..
  • escapar de la/como esta para hacer es como una lite ral \/
  • ¿Cuál es la | separador para? que está haciendo dos partes exclusivamente mutuos - ya sea un 'número entero' o un 'numtor' con un 'Dentor' ... esa parte parece confuso ...
+0

'/' no tiene ningún significado especial en expresiones regulares. Algunos sabores lo usan como un delimitador para regex * literales * (JavaScript, por ejemplo), pero en .NET es solo otro personaje; no tienes que escapar de eso. –

+0

Gracias por tomarse el tiempo para responder, pero no necesitaba analizar la expresión regular, solo para mostrar el problema en cuestión. – Dinah

Cuestiones relacionadas