C# 正则表达式

`Regex` 类、分组、替换、命名组、以及超时保护。

Intermediate
Key Points把 `Regex` 实例缓存成静态字段,别在循环里反复 `new` —— 编译有成本。

基本匹配

C#
using System.Text.RegularExpressions;

var re = new Regex(@"\d{3}-\d{4}");

Console.WriteLine(re.IsMatch("电话 555-1234"));
Console.WriteLine(re.Match("电话 555-1234").Value);

var all = re.Matches("555-1234 和 666-5678");
Console.WriteLine(all.Count);
foreach (Match m in all)
{
    Console.WriteLine(m.Value);
}
Output
True
555-1234
2
555-1234
666-5678

分组

C#
var re = new Regex(@"(\w+)@(\w+)\.com");

var m = re.Match("联系 tom@example.com");
Console.WriteLine(m.Success);
Console.WriteLine(m.Groups[0].Value);      // 整体
Console.WriteLine(m.Groups[1].Value);      // 第一组
Console.WriteLine(m.Groups[2].Value);      // 第二组
Output
True
tom@example.com
tom
example
C#
// 命名分组
var re = new Regex(@"(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})");
var m = re.Match("2026-10-31");

Console.WriteLine(m.Groups["year"].Value);
Console.WriteLine(m.Groups["month"].Value);
Console.WriteLine(m.Groups["day"].Value);
Output
2026
10
31

Named groups beat numeric indices: reorder the pattern and numeric indices break while names do not. Use names for anything non-trivial.

替换

C#
var re = new Regex(@"(\d{4})-(\d{2})-(\d{2})");

Console.WriteLine(re.Replace("2026-10-31", "$3/$2/$1"));

// 用委托做复杂替换
var result = re.Replace("2026-10-31", m => $"[{m.Groups[1].Value}年]");
Console.WriteLine(result);

// 去掉 HTML 标签
var tags = new Regex(@"<[^>]+>");
Console.WriteLine(tags.Replace("<p>你好</p>", ""));

// 转义用户输入
Console.WriteLine(Regex.Escape("1+1=2"));
Output
31/10/2026
[2026年]
你好
1\+1\=2
MethodReturns
IsMatchbool
Match第一个 Match
MatchesMatchCollection
Replace替换后的字符串
Split按正则拆分的数组
Regex.Escape转义特殊字符

选项

C#
// 忽略大小写
var re1 = new Regex("hello", RegexOptions.IgnoreCase);
Console.WriteLine(re1.IsMatch("HELLO"));

// 多行:^ 和 $ 匹配每行首尾
var re2 = new Regex(@"^\d+", RegexOptions.Multiline);
Console.WriteLine(re2.Matches("1\n22\n333").Count);

// 编译成 IL,启动慢但执行快(适合高频)
var re3 = new Regex(@"\d+", RegexOptions.Compiled);
Console.WriteLine(re3.Match("abc123").Value);

// 单行:. 能匹配换行
var re4 = new Regex(@"a.b", RegexOptions.Singleline);
Console.WriteLine(re4.IsMatch("a\nb"));
Output
True
3
123
True

超时保护

C#
try
{
    // 灾难性回溯的经典模式
    var bad = new Regex(@"^(a+)+$", RegexOptions.None, TimeSpan.FromMilliseconds(100));
    bad.IsMatch(new string('a', 30) + "b");
}
catch (RegexMatchTimeoutException)
{
    Console.WriteLine("正则超时,可能被 ReDoS 攻击");
}
Output
正则超时,可能被 ReDoS 攻击
Set a timeout on any regex that sees user input. Nested quantifiers like (a+)+$ backtrack exponentially on crafted input — one request pins a CPU (ReDoS). .NET accepts a TimeSpan in the constructor.

常用模式

C#
var patterns = new Dictionary<string, string>
{
    ["邮箱"] = @"^[\w.+-]+@[\w-]+\.[\w.]+$",
    ["手机号"] = @"^1[3-9]\d{9}$",
    ["身份证"] = @"^\d{17}[\dXx]$",
    ["IPv4"] = @"^((25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(25[0-5]|2[0-4]\d|[01]?\d?\d)$",
    ["URL"] = @"^https?://[\w.-]+(:\d+)?(/[\w./?%&=-]*)?$",
};

foreach (var (name, pattern) in patterns)
{
    var re = new Regex(pattern);
    Console.WriteLine($"{name}: {re.IsMatch("test@example.com")}");
}
Output
邮箱: True
手机号: False
身份证: False
IPv4: False
URL: False

Friends & Partners