提问人:superjugy 提问时间:11/7/2023 更新时间:11/11/2023 访问量:58
用于查找调用另一个特定函数的函数名称的正则表达式
Regex to find the name of functions that called another specific function
问:
假设您有一个具有多个方法的 C# 类。其中一些方法调用函数。我需要一个正则表达式来查找函数的名称,并且仅查找调用 DoWorkAsync 的函数。幸运的是,所有功能都具有相同的签名:并且都以保护措施结束。DoWorkAsync
public object %name%(List<object> params)
return null;
例如:
...
public object AddData(List<object> params) {
DoSomething();
DoSomething();
DoSomething();
return null;
}
public object ProcessData(List<object> params) {
DoSomething();
DoWorkAsync(); //this is an invocation
DoSomething();
return null;
}
public object RemoveData(List<object> params) {
DoSomething();
DoSomething();
DoSomething();
return null;
}
...
我首先尝试了这个简单的正则表达式(我使用的是 SingleLine Option,因此“.” 匹配新行):
@"public object (?'funcname'.+?)\(List<object> params\).+?DoWorkAsync\(\);"
这样做的问题是第一个函数将始终匹配,而不是因为它最终会在打开函数后找到对的调用。它不知道函数结束了,新函数开始了。好的,所以我读到了平衡正则表达式,它应该处理这种东西。然后我尝试了类似的东西:funcname
AddData
ProcessData
DoWorkAsync
@"(?:public object (?'funcname'.+?)\(List<object> params\)(?'count')|.+?DoWorkAsync\(\);.+?|return null;(?'-count'))*(?(count)(?!))"
这不起作用,因为它将再次匹配两个打开函数和两个关闭“return null”。如果它在没有首先找到函数调用的情况下找到返回值,我需要它失败。我尝试了其他排列,例如:
@"public object (?'funcname'.+?)\(List<object> params\).+?(?:public object .+?\(List<object> params\)(?!)|DoWorkAsync\(\);.+?).+?return null;"
但没有任何效果。我认为,如果我能够只过滤最深的层次,那么平衡正则表达式可能是答案。或者,如果平衡不起作用,则进行某种展望,以便在找到打开函数后,如果您在函数调用之前向前查看并找到另一个打开函数,则它将失败。
有人知道吗?谢谢。
答:
我能够弄清楚。不过,我必须做嵌套正则表达式。这是我所做的:
- 使用此正则表达式查找所有函数:
@"public object (?'name'\S+)\(List<object> params\){(?'function'(?:[^{}]*|{(?'depth')|}(?'-depth'))*(?(depth)(?!)))}"
- 使用我要替换的目标函数初始化队列:
var queue = new Queue<string>(); queue.Enqueue("DoWorkAsync");
- 使用 while 循环遍历队列:
while (queue.Count > 0) {
var toConvert = queue.Dequeue();
...
}
- 在 while 中,执行 for 循环以将调用该函数的任何函数添加到队列中:
foreach (var caller in functions.Where(m => m.Groups["function"].Value.Contains(toConvert)).Select(m => m.Groups["name"].Value)) {
queue.Enqueue(caller);
}
- 在 foreach 循环之后,但仍在 while 循环中,我只是对调用和定义进行替换:
newSource = Regex.Replace(oldSource, $@"{toConvert}\((?'params'(?:[^\(\)]*|\((?'depth')|\)(?'-depth'))*(?(depth)(?!)))\)", $"await {toConvert}(${{params}})");
newSource = Regex.Replace(newSource, $@"public object {toConvert}\(List<object> params\)", $"public async Task<object> {toConvert}(List<object> params)");
就是这样!
我发现的一个警告是,如果任何函数是递归的,它将将自己添加到队列中并无限循环。这可以通过拥有一组已转换的函数并在 foreach 中过滤掉它们来解决。
评论
Find usages
DoWorkAsync
Ctrl+F