C#开发:使用正则从C风格函数声明中提取任意数量形参名
C# 正则提取C风格函数形参名通用方案
不要试图用单条正则覆盖所有场景,这类C函数声明因为存在宏嵌套、类型修饰符组合、换行排版差异,单正则会写得极其冗长且难以维护,分层处理的方案通用性和可维护性高很多。
实现思路
分两步处理:先定位所有函数的参数列表块,再从单个参数声明里提取形参名,额外用极简单的计数逻辑处理宏括号内的逗号分割问题,比纯正则处理效率高、漏匹配概率低。
第一步:匹配函数的参数列表块
使用如下正则匹配函数声明,捕获组1会返回函数名后括号内的完整参数内容,自动兼容带嵌套括号的宏返回值(比如AUTOSAR的FUNC(xxx, yyy) 格式)、跨多行排版的声明:
(?:\w+\s+|\*|\)+)*\w+\s*\(([^)(]*?(?:\([^)(]*\)[^)(]*?)*)\)
对你提供的三个示例,该正则捕获到的参数块内容分别为:
NegativeResponseCode *ErrorCode_pt, uint8 Sid_u8P2CONST(uint8, AUTOMATIC, RTE_APPL_DATA) p_Data,\n P2VAR(Dcm_NegativeResponseCodeType, AUTOMATIC, RTE_APPL_DATA) ErrorCodeconst UBYTE* abc
如果捕获到的参数块为空、或仅为void,直接判定为无参数函数跳过即可。
第二步:分割单参数、提取形参名
拿到完整参数块后,不要直接用普通Split(',')分割——否则会把P2CONST这类宏内部的逗号误判为参数分隔符。写个10行左右的括号计数逻辑做分割:遍历字符串时遇到左括号计数+1,右括号计数-1,只有计数为0时遇到的逗号才是参数分隔符。
对分割后的单个参数字符串,用如下正则提取形参名,自动跳过所有前缀修饰:
(?:const\s+|volatile\s+)*\w+(?:\s*\([^)]*\))?\s*(?:\*+\s*|\s+)(\w+)\s*$
该正则可以覆盖的修饰场景包括:基础类型名、const/volatile类型限定符、带括号的参数/类型宏(P2CONST/P2VAR等)、任意数量的指针符号*,最终捕获组1的内容就是形参名。
对你的示例的匹配结果:
- 第一组参数:分别捕获
ErrorCode_pt、Sid_u8 - 第二组参数:分别捕获
p_Data、ErrorCode - 第三组参数:捕获
abc
C# 可直接运行的实现代码
using System; using System.Collections.Generic; using System.Text.RegularExpressions; public class FunctionParamExtractor { private static readonly Regex _functionMatcher = new Regex( @"(?:\w+\s+|\*|\)+)*\w+\s*\(([^)(]*?(?:\([^)(]*\)[^)(]*?)*)\)", RegexOptions.Compiled | RegexOptions.Multiline ); private static readonly Regex _paramNameMatcher = new Regex( @"(?:const\s+|volatile\s+)*\w+(?:\s*\([^)]*\))?\s*(?:\*+\s*|\s+)(\w+)\s*$", RegexOptions.Compiled ); public static List<string> GetAllParamNames(string sourceCode) { var paramNames = new List<string>(); foreach (Match funcMatch in _functionMatcher.Matches(sourceCode)) { string paramBlock = funcMatch.Groups[1].Value.Trim(); // 跳过无参数函数 if (string.IsNullOrWhiteSpace(paramBlock) || paramBlock.Equals("void", StringComparison.Ordinal)) continue; foreach (string singleParam in SplitParamBlock(paramBlock)) { var nameMatch = _paramNameMatcher.Match(singleParam.Trim()); if (nameMatch.Success) paramNames.Add(nameMatch.Groups[1].Value); } } return paramNames; } // 括号感知的逗号分割,避免宏内逗号被误判为参数分隔符 private static List<string> SplitParamBlock(string paramBlock) { var paramList = new List<string>(); int bracketCount = 0; int segmentStart = 0; for (int i = 0; i < paramBlock.Length; i++) { char current = paramBlock[i]; if (current == '(') bracketCount++; if (current == ')') bracketCount--; if (current == ',' && bracketCount == 0) { paramList.Add(paramBlock.Substring(segmentStart, i - segmentStart)); segmentStart = i + 1; } } paramList.Add(paramBlock.Substring(segmentStart)); return paramList; } }
方案适配范围
- 支持1到任意数量的函数参数
- 兼容AUTOSAR标准的FUNC、P2CONST、P2VAR等宏修饰写法
- 支持const/volatile修饰、多级指针、跨多行排版的函数声明
- 自动过滤无参数的函数声明
- 后续如果需要新增修饰符适配(比如
restrict关键字、自定义类型宏),只需要在参数名匹配的正则前缀部分追加对应规则即可,维护成本远低于单条全匹配正则。
内容的提问来源于stack exchange,提问作者Bruce
相关产品推荐
相关产品推荐

