带平衡组的正则表达式
Regex with balancing groups
我需要编写正则表达式来捕获类型名称的通用参数(也可以是通用的),特殊符号如下:
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)(?!)
)$
我建议使用
捕获这些值
\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 以外的字符=] 和 ]
,以及结束语 ]
.
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)(?!))])?))*
我需要编写正则表达式来捕获类型名称的通用参数(也可以是通用的),特殊符号如下:
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)(?!)
)$
我建议使用
捕获这些值\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 以外的字符=] 和]
,以及结束语]
.
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)(?!))])?))*