Можно ли улучшить этот код регулярного выражения C#?

В программе я читаю в некоторых файлах данных, часть которых отформатированы как серия записей каждый в квадратных скобках. Каждая запись содержит заголовок раздела и серию пар ключ/значение.

Я первоначально написал код, чтобы циклично выполниться через и извлечь значения, но решил, что он мог быть сделан более изящно использующие регулярные выражения. Ниже мой получающийся код (я просто вырубил его на данный момент в консольном приложении - поэтому знайте, что имена переменной не являются настолько большими и т.д.

Можно ли предложить улучшения? Я чувствую, что это не должно быть необходимо сделать два соответствия и подстроку, но не может выяснить, как сделать все это на одном большом шаге:

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);
    }
}
7
задан Carl Manaster 22 June 2009 в 22:37
поделиться

4 ответа

Я предпочитаю именованные захваты, хорошее форматирование и ясность:

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);           
    }
}
7
ответ дан 6 December 2019 в 19:41
поделиться

Вы должны воспользоваться коллекциями, чтобы получить каждый ключ. Тогда что-то вроде этого:

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

Результат:

section1
key1=value1
key2=value2
section2
key1=value1
key2=value2
key3=value3
section3
key1=value1
5
ответ дан 6 December 2019 в 19:41
поделиться

Вы должны уметь что-то делать с вложенными группами вроде этого:

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

Я не тестировал это на C # и не просматривал совпадения, но результаты выглядят правильно на rubular .com

2
ответ дан 6 December 2019 в 19:41
поделиться

Это будет соответствовать всем парам ключ / значение ...

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] );
    }
}
-1
ответ дан 6 December 2019 в 19:41
поделиться