在C#开发中,处理文本时经常遇到需要按照某种规则查找内容并改写的情况。正则表达式通过描述字符模式,让匹配与替换变得灵活且可控。System.Text.RegularExpressions下的Regex类封装了相关能力,既可以做单次匹配,也能做全局替换。

一、Regex类的基本匹配用法
Regex类最常用的静态方法包括IsMatch、Match和Matches。IsMatch用于判断字符串中是否存在符合规则的内容,适合做格式校验。比如校验输入是否为纯数字,可以用简单模式d+配合锚点。
当需要拿到匹配到的具体值时,应使用Match或Matches。Match返回第一个匹配结果,Matches返回所有匹配的集合。下面的代码演示了如何从一段文本中提取所有的数字:
using System;
using System.Text.RegularExpressions;
class Demo
{
static void Main()
{
string text = "订单号123,金额456,运费78";
// 匹配连续数字
MatchCollection matches = Regex.Matches(text, @"d+");
foreach (Match m in matches)
{
Console.WriteLine("找到数字:" + m.Value);
}
}
}
上述代码使用了@前缀的逐字字符串,避免反斜杠被当作转义符。如果不用@,则需要写成\d+。在匹配中文或特殊符号时,也要注意编码和字符类范围,例如[u4e00-u9fa5]可匹配常用汉字。
除了静态方法,也可以创建Regex实例并复用。当同一个模式要执行多次时,实例化能提升性能,因为编译后的正则对象可缓存。构造时还可传入RegexOptions.IgnoreCase实现忽略大小写匹配。
二、使用Replace完成字符串替换
Replace是最常用的改写方法,它有两种主要形式:传入替换字符串,或传入匹配处理函数。简单替换中,可以用$1这样的反向引用把分组内容放回结果里。
例如将日期格式从2024-01-02改为01/02/2024,可以用分组捕获并调整顺序。下面的示例展示了基础替换方式:
using System;
using System.Text.RegularExpressions;
class ReplaceDemo
{
static void Main()
{
string input = "日期:2024-01-02,日期:2023-12-15";
// 三个分组分别捕获年、月、日
string pattern = @"(d{4})-(d{2})-(d{2})";
string result = Regex.Replace(input, pattern, "$2/$3/$1");
Console.WriteLine(result);
}
}
代码中$1、$2、$3对应前面括号里的年、月、日分组。这种写法简洁直观,适合固定格式的重组。但如果替换逻辑依赖外部变量或计算,就需要用委托版本。
Regex.Replace还有一个重载,接收MatchEvaluator委托,每次匹配都会调用该方法并返回替换文本。下面示例将文本中的手机号中间四位脱敏:
using System;
using System.Text.RegularExpressions;
class MaskDemo
{
static void Main()
{
string input = "联系方式:13812345678,备用:13987654321";
string pattern = @"(1d{2})d{4}(d{4})";
string output = Regex.Replace(input, pattern, (Match m) =>
{
return m.Groups[1].Value + "****" + m.Groups[2].Value;
});
Console.WriteLine(output);
}
}
委托内部通过m.Groups拿到分组,拼接出脱敏结果。相比手动循环查找并截取,Regex配合委托减少了边界处理代码,也降低了出错概率。
三、常见误区与注意事项
写正则时最容易忽略的是特殊字符转义。点在正则里代表任意字符,如果要匹配真实的点号,必须写成.。在C#逐字字符串中即为@".",普通字符串则为"\."。
另一个误区是过度使用贪婪匹配。比如用<.*>去匹配HTML标签,会一口气吃到最后一个>。应改为非贪婪写法<.*?>,或明确字符范围如<[^>]+>。下面用表格列出几个易错点:
| 场景 | 易错写法 | 推荐写法 |
|---|---|---|
| 匹配点号 | . | . |
| 最小标签匹配 | <.*> | <.*?> |
| 数字范围 | d* | d+(至少一位) |
在替换含反向引用的字符串时,若美元符号后不是合法数字,也会被当作普通字符。如果替换文本本身包含$1字样且不想被解释,应使用$${1}或改用委托方式,避免歧义。
最后要注意Regex默认会区分大小写,需要忽略时务必传RegexOptions.IgnoreCase,或者在模式里用(?i)内联选项。多线程环境下,静态方法是线程安全的,实例方法在未被修改的前提下也可安全复用。
四、综合示例:提取并替换邮箱域名
假设有一批用户留言,其中邮箱域名需要统一替换为ipipp.com,同时保留账号名。我们可以结合分组与替换字符串一步完成。
using System;
using System.Text.RegularExpressions;
class EmailDemo
{
static void Main()
{
string text = "联系a@ippipp.com和b@test.org获取资料";
// 捕获@前账号,域名部分直接重写
string pattern = @"([a-zA-Z0-9_]+)@[a-zA-Z0-9.]+";
string result = Regex.Replace(text, pattern, "$1@ipipp.com");
Console.WriteLine(result);
}
}
运行后,两个邮箱都变为ipipp.com域名。此例说明只要分组设计合理,很多文本规范化任务可用一行Replace解决,不必写复杂解析器。
通过上述匹配与替换的演示,可以看到C#正则表达式在字符串处理上的表达力和简洁性。实际项目中建议把复杂模式提取为常量或配置,配合单元测试验证边界情况,才能保证规则长期稳定。