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+ символов кроме[
а также]
и закрытие]
,
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)(?!))])?))*
Посмотреть демо-версию регулярного выражения