带平衡组的正则表达式

Regex with balancing groups

我需要编写正则表达式来捕获类型名称的通用参数(也可以是通用的),特殊符号如下:

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

让我们假设类型名称是 [\w.]+ 并且参数是 [\w.,\[\]]+ 所以我只需要抓取 Int32Dictionary[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
)$

Demo

UPD2(上次优化)

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

我建议使用

捕获这些值
\w+(?:\.\w+)*\[(?:,?(?<res>\w+(?:\[[^][]*])?))*

参见regex demo

详情:

  • \w+(?:\.\w+)* - 匹配 1+ 个单词字符后跟 . + 1+ 个单词字符 1 次或更多次
  • \[ - 文字 [
  • (?:,?(?<res>\w+(?:\[[^][]*])?))* - 0 个或多个序列:
    • ,? - 一个可选的逗号
    • (?<res>\w+(?:\[[^][]*])?) - 组 "res" 捕获:
      • \w+ - 一个或多个单词字符(也许,您想要 [\w.]+
      • (?:\[[^][]*])? - 1 或 0(将 ? 更改为 * 以匹配 1 个或多个)a [ 的序列,0+ 个 [=16 以外的字符=] 和 ],以及结束语 ].

一个C# demo below:

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)(?!))])?))*

regex demo