C#中使用Switch语法糖结合正则判断格式的优化问题
正则匹配优化问题解答
先看原始代码:
var sampleName = "001-99-26Jul2023"; var sampleNameFormat1 = @"[0-9]{3}-(?<clientId>[0-9]{2})-[0-9]{2}[a-zA-Z]{3}[0-9]{4}"; var sampleNameFormat2 = @"[0-9]{4}-(?<clientId>[0-9]{2})-[0-9]{2}[a-zA-Z]{3}[0-9]{4}"; var sampleNameFormat3 = @"[0-9]{5}-[0-9]{2}[a-zA-Z]{3}[0-9]{4}"; var regexMatch = sampleName switch { var _ when Regex.IsMatch(sampleName, sampleNameFormat1, RegexOptions.IgnoreCase) => Regex.Match(sampleName, sampleNameFormat1, RegexOptions.IgnoreCase), var _ when Regex.IsMatch(sampleName, sampleNameFormat2, RegexOptions.IgnoreCase) => Regex.Match(sampleName, sampleNameFormat2, RegexOptions.IgnoreCase), var _ when Regex.IsMatch(sampleName, sampleNameFormat3, RegexOptions.IgnoreCase) => Regex.Match(sampleName, sampleNameFormat3, RegexOptions.IgnoreCase), _ => null, }; var clientIdString = regexMatch.Result("${clientId}"); if(!string.IsNullOrEmpty(clientIdString)) // 因sampleNameFormat3无<clientId>命名组需做判断 { int clientId = ParseInteger(clientIdString); }
针对你的两个问题,解答如下:
1. 避免重复正则匹配的优化方案
原始代码每个分支先调用Regex.IsMatch再调用Regex.Match,会执行两次匹配操作,完全可以优化为只调用一次Match并复用结果,提供两种方案:
方案一:模式匹配简化switch分支
直接在switch条件分支里调用Match,通过模式匹配判断是否匹配成功,同时捕获匹配结果:
var regexMatch = sampleName switch { _ when Regex.Match(sampleName, sampleNameFormat1, RegexOptions.IgnoreCase) is { Success: true } match => match, _ when Regex.Match(sampleName, sampleNameFormat2, RegexOptions.IgnoreCase) is { Success: true } match => match, _ when Regex.Match(sampleName, sampleNameFormat3, RegexOptions.IgnoreCase) is { Success: true } match => match, _ => null };
方案二:正则列表循环匹配(更易扩展)
如果后续要新增格式,把正则表达式放到列表里循环匹配会更简洁,每个正则仅执行一次Match:
var regexList = new List<Regex> { new Regex(sampleNameFormat1, RegexOptions.IgnoreCase), new Regex(sampleNameFormat2, RegexOptions.IgnoreCase), new Regex(sampleNameFormat3, RegexOptions.IgnoreCase) }; var regexMatch = regexList.Select(r => r.Match(sampleName)) .FirstOrDefault(match => match.Success);
2. 命名组不存在时的处理方式
改用regexMatch.Groups["clientId"].Value的处理方式是正确的,还可以优化得更严谨:
- 当正则不包含
clientId命名组时,Groups["clientId"]会返回一个Group对象,其Value属性为空字符串,!string.IsNullOrEmpty判断可以正确跳过format_3的情况。 - 额外建议:先判断
regexMatch是否为null,再检查命名组是否存在,避免空引用异常:
if (regexMatch != null && regexMatch.Groups.ContainsKey("clientId") && !string.IsNullOrEmpty(regexMatch.Groups["clientId"].Value)) { int clientId = ParseInteger(regexMatch.Groups["clientId"].Value); }
这样既覆盖了regexMatch为null(无匹配格式)的场景,又明确确认命名组存在后再取值,逻辑更清晰。
内容的提问来源于stack exchange,提问作者Mihai Socaciu
相关产品推荐
相关产品推荐

