C# 正则表达式(3):分组与捕获——从子串提取到命名分组

一、分组是什么:让一段模式成为"一个单元"

1. 普通分组:(...)

分组最直接的作用是"打包",使用()完成打包,一个括号就是一个分组。例如你想匹配 ab 重复多次:

  • 错误:ab+ 只会让 b 重复
  • 正确:(ab)+ab 作为整体重复

2. 分组 + 量词:控制重复结构

示例:匹配 2025-12-18 这种日期结构

regex 复制代码
(\d{4})-(\d{2})-(\d{2})

解析:

  • 这里有 3 个分组:年、月、日。它们不仅能帮助你"读懂结构",更重要的是能在代码里提取出来。

二、捕获组:Match.Groups 到底是什么?

示例:

csharp 复制代码
using System;
using System.Text.RegularExpressions;

var input = "2025-12-18";
var pattern = @"^(\d{4})-(\d{2})-(\d{2})$";

Match match = Regex.Match(input, pattern);
if (!match.Success)
{
    Console.WriteLine("No match");
    return;
}

Console.WriteLine($"Full: {match.Groups[0].Value}");
Console.WriteLine($"Year: {match.Groups[1].Value}");
Console.WriteLine($"Month:{match.Groups[2].Value}");
Console.WriteLine($"Day:  {match.Groups[3].Value}");

解析:

  • Groups[0] 永远是"整个匹配到的字符串"
  • Groups[1] 开始才是你写的第 1、2、3... 个捕获组

三、命名分组:让提取更稳、更好维护

当分组多了以后,Groups[7] 这种写法非常容易错。命名分组就是解决这个问题的。

语法:

regex 复制代码
(?<name>...)

把上面的日期改成命名分组:

csharp 复制代码
var input = "2025-12-18";
var input = "2025-12-18";
var pattern = @"^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$";

Match match = Regex.Match(input, pattern);
Console.WriteLine(match.Groups["year"].Value);  // 2025
Console.WriteLine(match.Groups["month"].Value); // 12
Console.WriteLine(match.Groups["day"].Value);   // 18

// 依然可以用序号访问到目标内容
Console.WriteLine($"Full: {match.Groups[0].Value}");
Console.WriteLine($"Year: {match.Groups[1].Value}");
Console.WriteLine($"Month:{match.Groups[2].Value}");
Console.WriteLine($"Day:  {match.Groups[3].Value}");

四、Regex.Replace 的"重排": <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 与 1 与 </math>1与{name}

1. 按序号引用:$1$2...

序号从1开始

csharp 复制代码
var input = "2025-12-18";
var pattern = @"^(\d{4})-(\d{2})-(\d{2})$";

var output = Regex.Replace(input, pattern, "$3/$2/$1");
Console.WriteLine(output); // 18/12/2025

2. 按名称引用:${year}${month}...

csharp 复制代码
var input = "2025-12-18";
var pattern = @"^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$";

var output = Regex.Replace(input, pattern, "${day}/${month}/${year}");
Console.WriteLine(output); // 18/12/2025

五、非捕获分组:(?:...)

当我们想匹配整体,并且分组内容不存入 Groups 集合。此时用非捕获分组:

regex 复制代码
(?:...)

示例:

csharp 复制代码
string input = "I love C# and I love Java";

// 使用非捕获分组 (?:C#|Java)
// 它只是为了让 | (或) 逻辑生效,而不建立单独的提取组
string pattern = @"I love (?:C#|Java)";

MatchCollection matches = Regex.Matches(input, pattern);

foreach (Match m in matches)
{
    Console.WriteLine($"完全匹配内容: {m.Value}");
    Console.WriteLine($"分组数量: {m.Groups.Count}"); // 索引 0 永远是完整匹配,并且只有一个,没有为C#|Java单独分组
}
/*输出
完全匹配内容: I love C#
分组数量: 1
完全匹配内容: I love Java
分组数量: 1
*/

结语

点个赞,关注我获取更多实用 C# 技术干货!如果觉得有用,记得收藏本文

相关推荐
cxxcode14 小时前
Vite 热更新(HMR)原理详解
前端
HelloReader14 小时前
Tauri 架构从“WebView + Rust”到完整工具链与生态
前端
Bigger14 小时前
告别版本焦虑:如何为 Hugo 项目定制专属构建环境
前端·架构·go
Scout-leaf15 小时前
WPF新手村教程(三)—— 路由事件
c#·wpf
代码匠心16 小时前
AI 自动编程:一句话设计高颜值博客
前端·ai·ai编程·claude
_AaronWong17 小时前
Electron 实现仿豆包划词取词功能:从 AI 生成到落地踩坑记
前端·javascript·vue.js
cxxcode17 小时前
I/O 多路复用:从浏览器到 Linux 内核
前端
用户54330814419417 小时前
AI 时代,前端逆向的门槛已经低到离谱 — 以 Upwork 为例
前端
JarvanMo18 小时前
Flutter 版本的 material_ui 已经上架 pub.dev 啦!快来抢先体验吧。
前端
恋猫de小郭18 小时前
AI 可以让 WIFI 实现监控室内人体位置和姿态,无需摄像头?
前端·人工智能·ai编程