2009-06-22 11 views
7

En un programa que estoy leyendo en algunos archivos de datos, parte de los cuales están formateados como una serie de registros, cada uno entre corchetes. Cada registro contiene un título de sección y una serie de pares clave/valor.¿Se puede mejorar este código de expresión regular C#?

Originalmente escribí código para recorrer y extraer los valores, pero decidí que se podía hacer de forma más elegante utilizando expresiones regulares. A continuación está mi código resultante (lo acabo de hackear por ahora en una aplicación de consola, así que sé que los nombres de las variables no son tan buenos, etc.

¿Puedes sugerir mejoras? Creo que no debería ser necesario hacerlo dos partidos y una subcadena, pero no puede encontrar la manera de hacerlo todo en un gran paso:

string input = "[section1 key1=value1 key2=value2][section2 key1=value1 key2=value2 key3=value3][section3 key1=value1]"; 

MatchCollection matches=Regex.Matches(input, @"\[[^\]]*\]"); 
foreach (Match match in matches) 
{ 
    string subinput = match.Value; 

    int firstSpace = subinput.IndexOf(' '); 
    string section = subinput.Substring(1, firstSpace-1); 
    Console.WriteLine(section); 

    MatchCollection newMatches = Regex.Matches(subinput.Substring(firstSpace + 1), @"\s*(\w+)\s*=\s*(\w+)\s*"); 
    foreach (Match newMatch in newMatches) 
    { 
     Console.WriteLine("{0}={1}", newMatch.Groups[1].Value, newMatch.Groups[2].Value); 
    } 
} 

Respuesta

7

prefiero capturas con nombre, buen formato, y claridad:

string input = "[section1 key1=value1 key2=value2][section2 key1=value1 key2=value2 key3=value3][section3 key1=value1]"; 
MatchCollection matches = Regex.Matches(input, @"\[ 
                (?<sectionName>\S+) 
                 (\s+                
                 (?<key>[^=]+) 
                  = 
                 (?<value>[^ \] ]+)              
                )+ 
                ]", RegexOptions.IgnorePatternWhitespace); 

foreach(Match currentMatch in matches) 
{ 
    Console.WriteLine("Section: {0}", currentMatch.Groups["sectionName"].Value); 
    CaptureCollection keys = currentMatch.Groups["key"].Captures; 
    CaptureCollection values = currentMatch.Groups["value"].Captures; 

    for(int i = 0; i < keys.Count; i++) 
    { 
     Console.WriteLine("{0}={1}", keys[i].Value, values[i].Value);   
    } 
} 
+0

Bien, no sabía sobre usar la opción IgnorePatternWhitespace para permitirte formatear una expresión regular como esa. Gracias por el consejo. –

+0

+1 nuevamente para el RegexOptions.IgnorePatternWhitespace, sí para la legibilidad –

+0

+1 Yo también prefiero las capturas con nombre. Hacen que el código sea legible y fácil de entender. –

2

Usted debe ser capaz de hacer algo con los grupos anidados como esto:

pattern = @"\[(\S+)(\s+([^\s=]+)=([^\s\]]+))*\]" 

I no lo han probado en C# ni han pasado por las cerillas, pero los resultados se ven bien en rubular.com

+0

+1 para el enlace. –

5

Debe aprovechar las colecciones para obtener cada clave. Así que algo como esto, entonces: salida

 string input = "[section1 key1=value1 key2=value2][section2 key1=value1 key2=value2 key3=value3][section3 key1=value1]"; 

     Regex r = new Regex(@"(\[(\S+) (\s*\w+\s*=\s*\w+\s*)*\])", RegexOptions.Compiled); 

     foreach (Match m in r.Matches(input)) 
     { 
      Console.WriteLine(m.Groups[2].Value); 
      foreach (Capture c in m.Groups[3].Captures) 
      { 
       Console.WriteLine(c.Value); 
      } 
     } 

resultante:

section1 
key1=value1 
key2=value2 
section2 
key1=value1 
key2=value2 
key3=value3 
section3 
key1=value1 
-1

Esto corresponderá con todos los pares clave/valor ...

var input = "[section1 key1=value1 key2=value2][section2 key1=value1 key2=value2 key3=value3][section3 key1=value1]"; 

var ms = Regex.Matches(input, @"section(\d+)\s*(\w+=\w+)\s*(\w+=\w+)*"); 

foreach (Match m in ms) 
{ 
    Console.WriteLine("Section " + m.Groups[1].Value); 

    for (var i = 2; i < m.Groups.Count; i++) 
    { 
     if(!m.Groups[i].Success) continue; 
     var kvp = m.Groups[i].Value.Split('='); 
     Console.WriteLine("{0}={1}", kvp[0], kvp[1]); 
    } 
} 
Cuestiones relacionadas