C# 正则表达式(Regular Expressions)
                           
天天向上
发布: 2025-04-13 14:39:41

原创
9 人浏览过

本章节重点讲解 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|ba 或 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 编辑器调试

十一、推荐工具及资源


十二、官方文档链接

更多详细内容请关注其他相关文章!

发表回复 0

Your email address will not be published. Required fields are marked *