C# 中的正则表达式(Regex)不是必须学,但一旦用对了,能省下大量字符串处理代码。它本质是用一套紧凑语法描述文本模式,再由 .NET 的
System.Text.RegularExpressions.Regex类执行匹配、提取、替换等操作。关键不在于背所有符号,而在于掌握高频场景下的写法和避坑点。
常用模式:从身份证、手机号到邮箱,怎么写才靠谱
写正则第一原则:**够用且不过度严格**。比如验证手机号,国内主流是 1[3-9]d{9},但别硬套“必须11位+首位1+第二位3-9”,因为携号转网后可能有新号段;验证邮箱用
[^s@]+@[^s@]+.[^s@]+就比 RFC 5322 标准简化版更实用——后者太长,且多数业务根本不需要支持引号包裹的用户名或 IP 形式域名。 中文姓名:
^[u4e00-u9fa5]{2,4}$(2–4个汉字,不含空格标点)
身份证号(18位):^d{17}[dXx]$(末位可能是 X,注意大小写)
日期(YYYY-MM-DD):^d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]d|3[01])$(仅格式校验,不判断闰年或每月天数)
URL 简化版:^https?://[^s/$.?#].[^s]*$(跳过协议后校验是否有域名主体)
匹配方法选哪个?Match、Matches、IsMatch、Replace 各干啥
不用死记 API,按目标选:
只关心“有没有匹配” → 用Regex.IsMatch(input, pattern),返回 bool,最快最轻量 要取第一个匹配内容(含分组) →
Regex.Match(input, pattern),返回
Match对象,
.Success判断是否成功,
.Value拿全文,
.Groups[1].Value拿第一个捕获组 要找所有匹配 →
Regex.Matches(input, pattern),返回
MatchCollection,可 foreach 遍历 要批量替换 →
Regex.Replace(input, pattern, replacement),replacement 可以是字符串,也可以是
MatchEvaluator委托实现动态逻辑(比如把所有数字加括号)
注意:如果 pattern 固定且反复使用,建议实例化
Regex对象并启用
RegexOptions.Compiled(首次编译慢,后续快),或直接用静态方法——.NET Core 6+ 对静态调用做了缓存优化,日常小项目够用。
捕获组与命名组:不只是“取内容”,更是结构化提取
用
()是捕获组,按左括号顺序编号(
Groups[0]是整个匹配,
Groups[1]是第一个
())。但写多了容易乱,推荐命名组:
(?<year>d{4})-(?<month>d{2})-(?<day>d{2})</day></month></year>。匹配后可通过 match.Groups["year"].Value直接读年份,语义清晰,重构友好。
还常配合
RegexOptions.IgnoreCase(忽略大小写)、
RegexOptions.Multiline(^$ 匹配每行起止)等选项使用。例如多行日志里找 ERROR 行:
^.*ERROR.*$+
Multiline,否则 ^$ 只匹配整个字符串头尾。
容易踩的坑:转义、贪婪、性能这三座山
正则里反斜杠是元字符,C# 字符串又吃反斜杠,所以写
d要么用双反斜杠
"\d",要么用逐字字符串
@ "d"——后者更清爽,推荐。 贪婪匹配默认吃最多,比如
a.*b在
a123b456b中会匹配整串;想只到第一个 b,改成懒惰模式:
a.*?b避免灾难性回溯:像
(a+)+b这类嵌套量词在坏输入下会让引擎指数级尝试,改用原子组
(?>a+)+b或重写逻辑(比如先找 a 再找 b) 简单场景别硬上正则:用
string.Contains、
string.StartsWith或
int.TryParse更快更安全;正则适合“模糊结构识别”,比如日志行中提取多个字段
基本上就这些。正则不是银弹,但它是文本处理工具箱里最锋利的小刀——磨熟了,切哪都快。
