Regex с балансировочными группами

Мне нужно написать регулярное выражение, которое захватывает общие аргументы (которые также могут быть универсальными) типа name в специальной записи, как это:

System.Action[Int32,Dictionary[Int32,Int32],Int32]

давайте предположим, что имя типа [\w.]+ и параметр [\w.,\[\]]+так что мне нужно только захватить Int32, Dictionary[Int32,Int32] а также Int32

По сути, мне нужно что-то предпринять, если стек балансировки группы пуст, но я не совсем понимаю, как это сделать.

UPD

Ответ ниже помог мне быстро решить проблему (но без надлежащей проверки и с ограничением глубины = 1), но мне удалось сделать это с групповой балансировкой:

^[\w.]+                                              #Type name
\[(?<delim>)                                         #Opening bracet and first delimiter
[\w.]+                                               #Minimal content
(
[\w.]+                                                       
((?(open)|(?<param-delim>)),(?(open)|(?<delim>)))*   #Cutting param if balanced before comma and placing delimiter
((?<open>\[))*                                       #Counting [
((?<-open>\]))*                                      #Counting ]
)*
(?(open)|(?<param-delim>))\]                         #Cutting last param if balanced
(?(open)(?!)                                         #Checking balance
)$

демонстрация

UPD2 (последняя оптимизация)

^[\w.]+
\[(?<delim>)
[\w.]+
(?:
 (?:(?(open)|(?<param-delim>)),(?(open)|(?<delim>))[\w.]+)?
 (?:(?<open>\[)[\w.]+)?
 (?:(?<-open>\]))*
)*
(?(open)|(?<param-delim>))\]
(?(open)(?!)
)$

1 ответ

Решение

Я предлагаю захватить эти значения с помощью

\w+(?:\.\w+)*\[(?:,?(?<res>\w+(?:\[[^][]*])?))*

Смотрите демо-версию регулярного выражения.

Подробности:

  • \w+(?:\.\w+)* - соответствовать 1+ словам, за которыми следуют . + 1+ слово символы 1 или более раз
  • \[ - буквальный [
  • (?:,?(?<res>\w+(?:\[[^][]*])?))* - 0 или более последовательностей:
    • ,? - необязательная запятая
    • (?<res>\w+(?:\[[^][]*])?) - Группа "Рес" захватывает:
      • \w+ - одно или несколько символов слова (возможно, вы хотели бы [\w.]+)
      • (?:\[[^][]*])? - 1 или 0 (изменить ? в * чтобы соответствовать 1 или более) последовательностей [, 0+ символов кроме [ а также ]и закрытие ],

Демо C# ниже:

var line = "System.Action[Int32,Dictionary[Int32,Int32],Int32]";
var pattern = @"\w+(?:\.\w+)*\[(?:,?(?<res>\w+(?:\[[^][]*])?))*";
var result = Regex.Matches(line, pattern)
        .Cast<Match>()
        .SelectMany(x => x.Groups["res"].Captures.Cast<Capture>()
            .Select(t => t.Value))
        .ToList();
foreach (var s in result) // DEMO
    Console.WriteLine(s);

ОБНОВЛЕНИЕ: для учета неизвестной глубины [...] подстроки, используйте

\w+(?:\.\w+)*\[(?:\s*,?\s*(?<res>\w+(?:\[(?>[^][]+|(?<o>\[)|(?<-o>]))*(?(o)(?!))])?))*

Посмотреть демо-версию регулярного выражения

Другие вопросы по тегам