C# 正则表达式(Regular Expressions)
本章节重点讲解 C# 正则表达式(Regular Expressions) ,包括:
- 基本原理
- 常用方法和类
- 实例讲解
- 匹配模式说明
- 性能优化建议
- 多途径实践方法
- 官方文档链接
- 实战案例
一、 什么是正则表达式?
正则表达式是一种用于描述文本模式的字符串规则,可以高效地执行:
- 字符串匹配
- 字符串提取
- 字符串替换
- 输入验证等任务
二、所用命名空间与类
C# 中使用正则表达式需引用:
using System.Text.RegularExpressions;
核心类如下:
| 类名 | 功能 |
|---|---|
Regex | 正则表达式主类 |
Match | 表示一次匹配结果 |
MatchCollection | 表示多个匹配结果 |
Group | 匹配结果的子表达式 |
RegexOptions | 控制匹配行为的枚举 |
三、常用构造函数与方法
3.1 创建 Regex 实例
Regex regex = new Regex(@"\d+"); // 匹配数字
3.2 静态方法(推荐)
bool isMatch = Regex.IsMatch("abc123", @"\d+"); // true
string[] result = Regex.Split("one,two;three", @"[,;]");
string replaced = Regex.Replace("hello 123", @"\d+", "###");
Match match = Regex.Match("abc123def", @"\d+");
四、常用正则表达式语法
| 表达式 | 匹配内容 |
|---|---|
. | 任意单字符(不含换行) |
\d | 数字(0-9) |
\w | 单词字符(字母、数字、下划线) |
\s | 空白字符 |
^ | 开始位置 |
$ | 结束位置 |
[abc] | 匹配 a、b 或 c |
[^abc] | 不匹配 a、b、c |
(abc) | 捕获组 |
a|b | a 或 b |
{n} | 重复 n 次 |
? | 可有可无(0或1次) |
* | 任意次数 |
+ | 至少 1 次 |
五、示例:常见正则表达式
| 用途 | 正则表达式 |
|---|---|
| 邮箱 | ^[\w.-]+@[\w.-]+\.\w{2,}$ |
| 手机号(中国) | ^1[3-9]\d{9}$ |
| IPv4 地址 | ^(\d{1,3}\.){3}\d{1,3}$ |
| 身份证号(简略) | ^\d{15}|\d{18}$ |
| 日期(YYYY-MM-DD) | ^\d{4}-\d{2}-\d{2}$ |
六、Match 示例(捕获数据)
string text = "Name: Alice, Age: 30";
Match match = Regex.Match(text, @"Name:\s(\w+),\sAge:\s(\d+)");
if (match.Success)
{
string name = match.Groups[1].Value;
string age = match.Groups[2].Value;
Console.WriteLine($"Name: {name}, Age: {age}");
}
七、RegexOptions(匹配选项)
Regex.IsMatch("abc", "ABC", RegexOptions.IgnoreCase); // 忽略大小写
Regex.IsMatch("abc\ndef", "^def", RegexOptions.Multiline); // 多行匹配
常用枚举:
| 枚举名 | 功能 |
|---|---|
IgnoreCase | 不区分大小写 |
Multiline | 多行模式 |
Singleline | . 匹配换行 |
Compiled | 编译成程序集(性能优化) |
CultureInvariant | 忽略区域性文化设置 |
八、性能优化建议
- 尽量使用静态方法(避免频繁创建
Regex实例) - 使用
RegexOptions.Compiled预编译表达式(适合大量调用) - 简化正则表达式,避免嵌套过深
- 使用
Timeout防止 ReDoS(正则拒绝服务攻击)
Regex regex = new Regex(@"\d+", RegexOptions.Compiled, TimeSpan.FromSeconds(1));
九、实战案例
1. 捕获组与命名组详解
匿名捕获组 ()
Match m = Regex.Match("2025-04-13", @"(\d{4})-(\d{2})-(\d{2})");
Console.WriteLine(m.Groups[1].Value); // 年
Console.WriteLine(m.Groups[2].Value); // 月
Console.WriteLine(m.Groups[3].Value); // 日
命名捕获组 (?<name>...)
string pattern = @"(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})";
Match match = Regex.Match("2025-04-13", pattern);
Console.WriteLine(match.Groups["year"].Value); // 输出 2025
2. 实战案例1:表单验证(邮箱 + 手机)
场景:在注册页面中验证用户输入
string email = "user@example.com";
string phone = "13812345678";
bool validEmail = Regex.IsMatch(email, @"^[\w\.-]+@[\w\.-]+\.\w{2,}$");
bool validPhone = Regex.IsMatch(phone, @"^1[3-9]\d{9}$");
Console.WriteLine($"邮箱合法:{validEmail}, 手机合法:{validPhone}");
3. 实战案例2:从日志中提取时间与IP
场景:日志分析系统,抽取时间戳与 IP
日志内容:
[2025-04-13 15:42:10] INFO Request from 192.168.1.55 processed.
提取代码:
string log = "[2025-04-13 15:42:10] INFO Request from 192.168.1.55 processed.";
string pattern = @"\[(?<datetime>.+?)\].+?(?<ip>\d+\.\d+\.\d+\.\d+)";
Match m = Regex.Match(log, pattern);
Console.WriteLine($"时间: {m.Groups["datetime"].Value}, IP: {m.Groups["ip"].Value}");
4. 实战案例3:批量从文件中提取邮箱地址
string[] lines = File.ReadAllLines("sample.txt");
Regex regex = new Regex(@"[\w\.-]+@[\w\.-]+\.\w+");
foreach (string line in lines)
{
foreach (Match m in regex.Matches(line))
{
Console.WriteLine($"找到邮箱: {m.Value}");
}
}
5. 实战案例4:网页爬虫中提取超链接
string html = "<a href=\"https://example.com\">Example</a>";
string pattern = @"<a\s+[^>]*href\s*=\s*[""']?(?<url>[^""'>\s]+)[""']?";
MatchCollection matches = Regex.Matches(html, pattern);
foreach (Match match in matches)
{
Console.WriteLine($"URL: {match.Groups["url"].Value}");
}
6. 实战案例5:与 ASP.NET Core 表单验证结合
[RegularExpression(@"^\d{15}|\d{18}$", ErrorMessage = "身份证格式不正确")]
public string IDCard { get; set; }
配合前端 Blazor 或 Razor Pages 自动验证。
7. 使用 MatchEvaluator 动态替换
string input = "价格为:$100, $200";
string result = Regex.Replace(input, @"\$(\d+)", m =>
{
int price = int.Parse(m.Groups[1].Value);
return $"¥{price * 7}";
});
Console.WriteLine(result); // 价格为:¥700, ¥1400
8. 性能优化建议
| 技术 | 建议 |
|---|---|
| 编译优化 | 使用 RegexOptions.Compiled |
| 表达式缓存 | 可静态定义 Regex 对象,避免重复编译 |
| 超时控制 | 推荐设置超时限制防止 ReDoS 攻击 |
| 简洁设计 | 正则尽量避免使用回溯较多的写法(如嵌套 *+?) |
Regex regex = new Regex(@"\d+", RegexOptions.Compiled, TimeSpan.FromSeconds(1));
十、真实项目场景 + 技术集成指南
1. 实战案例:完整的表单验证系统(ASP.NET Core MVC)
场景:用户注册页面验证用户名、密码、手机号、邮箱
📌 模型定义(Models/UserViewModel.cs)
public class UserViewModel
{
[Required]
[RegularExpression(@"^[a-zA-Z][a-zA-Z0-9_]{4,15}$", ErrorMessage = "用户名必须为5-16位字母、数字、下划线")]
public string Username { get; set; }
[Required]
[RegularExpression(@"^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{6,20}$", ErrorMessage = "密码必须为6-20位字母和数字组合")]
public string Password { get; set; }
[Required]
[RegularExpression(@"^1[3-9]\d{9}$", ErrorMessage = "无效的手机号")]
public string PhoneNumber { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
}
📌 控制器验证逻辑
[HttpPost]
public IActionResult Register(UserViewModel model)
{
if (!ModelState.IsValid)
return View(model);
// 注册成功逻辑
return RedirectToAction("Success");
}
📌 视图表单(Razor)
<form asp-action="Register">
<input asp-for="Username" />
<span asp-validation-for="Username"></span>
<!-- 其他字段... -->
</form>
2. 实战案例:批量校验并重写 CSV 文件字段
场景:识别无效邮箱并标记为“无效邮箱”
string[] lines = File.ReadAllLines("users.csv");
Regex emailRegex = new Regex(@"^[\w\.-]+@[\w\.-]+\.\w{2,}$");
List<string> updated = new();
foreach (string line in lines)
{
var fields = line.Split(',');
if (!emailRegex.IsMatch(fields[2])) // 假设第3列是邮箱
{
fields[2] = "无效邮箱";
}
updated.Add(string.Join(",", fields));
}
File.WriteAllLines("users_clean.csv", updated);
3. 实战案例:日志系统正则匹配 + LINQ 整合处理
string[] logs = File.ReadAllLines("app.log");
Regex logRegex = new Regex(@"\[(?<level>INFO|ERROR|DEBUG)\]\s+(?<message>.+)");
var errors = logs
.Select(line => logRegex.Match(line))
.Where(m => m.Success && m.Groups["level"].Value == "ERROR")
.Select(m => m.Groups["message"].Value);
foreach (var err in errors)
Console.WriteLine($"❌ 错误:{err}");
4. 实战案例:RESTful API 接口中正则验证上传数据
[HttpPost]
public IActionResult Upload([FromBody] JObject data)
{
string name = data["name"]?.ToString() ?? "";
string email = data["email"]?.ToString() ?? "";
if (!Regex.IsMatch(name, @"^[\u4e00-\u9fa5a-zA-Z\s]{2,20}$"))
return BadRequest("姓名格式不合法");
if (!Regex.IsMatch(email, @"^[\w\.-]+@[\w\.-]+\.\w+$"))
return BadRequest("邮箱格式不合法");
return Ok("✅ 上传成功");
}
5. 实用技巧:编译正则 + 缓存机制提升性能
private static readonly Regex _urlRegex = new Regex(@"https?://[^\s]+",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static IEnumerable<string> ExtractUrls(string content)
{
return _urlRegex.Matches(content).Select(m => m.Value);
}
推荐使用编译正则 RegexOptions.Compiled + 静态字段缓存,尤其在高频调用中。
6. 正则表达式工具类封装(复用性)
public static class RegexUtils
{
private static Regex phoneRegex = new(@"^1[3-9]\d{9}$", RegexOptions.Compiled);
private static Regex emailRegex = new(@"^[\w\.-]+@[\w\.-]+\.\w+$", RegexOptions.Compiled);
public static bool IsValidPhone(string input) => phoneRegex.IsMatch(input);
public static bool IsValidEmail(string input) => emailRegex.IsMatch(input);
}
7. 安全与性能注意事项
| 事项 | 说明 |
|---|---|
| 避免 ReDoS | 使用 Regex 构造函数指定 TimeSpan timeout |
尽量避免 .*? 嵌套 | 可能导致回溯爆炸 |
使用 RegexOptions.Compiled | 提升性能,避免频繁解析 |
| 表达式验证测试 | 使用 Regex101 或 Visual Studio 的 Regex 编辑器调试 |
十一、推荐工具及资源
- Microsoft 正则表达式文档(中文)
- Regex101 在线测试工具
- OWASP ReDoS 安全建议
- Regex in .NET GitHub Source
- Regex101(支持 C# 模式)
- Debuggex
- Microsoft 正则表达式语法参考
十二、官方文档链接
更多详细内容请关注其他相关文章!