2009-06-22 7 views
7

Dans un programme, je lis dans certains fichiers de données, dont une partie est formatée comme une série d'enregistrements entre crochets. Chaque enregistrement contient un titre de section et une série de paires clé/valeur.Pouvez-vous améliorer ce code d'expression régulière C#?

A l'origine, j'ai écrit du code pour faire une boucle et extraire les valeurs, mais j'ai décidé que cela pourrait être fait plus élégamment en utilisant des expressions régulières. Ci-dessous est mon code résultant (je l'ai juste piraté pour le moment dans une application de la console - donc connaître les noms de variables ne sont pas géniaux, etc

Pouvez-vous suggérer des améliorations? Je pense qu'il ne devrait pas être nécessaire de faire deux matches et une sous-chaîne, mais ne peuvent pas comprendre comment le faire tout en un grand pas:

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); 
    } 
} 

Répondre

7

Je préfère nommés capture, belle mise en forme, et clarté:

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, je ne savais pas utiliser l'option IgnorePatternWhitespace pour vous permettre de formater une regex comme ça. Merci pour le conseil. –

+0

+1 à nouveau pour le RegexOptions.IgnorePatternWhitespace ouais pour la lisibilité –

+0

+1 Je préfère aussi les captures nommées. Ils rendent le code lisible et facile à comprendre. –

2

Vous devriez être en mesure de faire quelque chose avec des groupes imbriqués comme ceci:

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

I ne l'ai pas testé en C# ou en boucle à travers les matchs, mais les résultats sont corrects sur rubular.com

+0

+1 pour le lien. –

5

Vous devriez tirer parti des collections pour obtenir chaque clé. Donc, quelque chose comme ça alors:

 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); 
      } 
     } 

résultante sortie:

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

Cela correspondra toutes les paires clé/valeur ...

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]); 
    } 
} 
Questions connexes