正则表达式(Regular Expression)是处理字符串的强大工具,C#通过System.Text.RegularExpressions
命名空间提供了完整的正则表达式支持。本教程将全面介绍如何在C#中使用正则表达式。
一、正则表达式基础
1.1 基本概念
正则表达式是描述字符模式的一种语法,可以用来:
- 验证字符串是否符合特定格式
- 查找和提取字符串中的特定部分
- 替换字符串中的内容
1.2 C#中的正则表达式类
C#主要提供以下类来处理正则表达式:
Regex
:表示不可变的正则表达式Match
:表示单个正则表达式匹配的结果MatchCollection
:表示通过迭代方式应用正则表达式到输入字符串所找到的成功匹配的集合Group
:表示单个捕获组的结果Capture
:表示单个子表达式捕获的结果
二、创建和使用正则表达式
2.1 基本使用方法
using System.Text.RegularExpressions;
// 简单匹配示例
string pattern = @"\d+"; // 匹配一个或多个数字
string input = "There are 123 apples and 456 oranges.";
bool isMatch = Regex.IsMatch(input, pattern); // 检查是否匹配
Console.WriteLine(isMatch); // 输出: True
Match match = Regex.Match(input, pattern); // 获取第一个匹配
Console.WriteLine(match.Value); // 输出: 123
MatchCollection matches = Regex.Matches(input, pattern); // 获取所有匹配
foreach (Match m in matches)
{
Console.WriteLine(m.Value);
}
// 输出:
// 123
// 456
2.2 编译正则表达式
对于频繁使用的正则表达式,可以编译以提高性能:
Regex compiledRegex = new Regex(pattern, RegexOptions.Compiled);
三、常用正则表达式语法
3.1 字符匹配
表达式 | 说明 |
---|---|
. | 匹配除换行符外的任意字符 |
\d | 匹配数字(0-9) |
\D | 匹配非数字 |
\w | 匹配字母、数字、下划线 |
\W | 匹配非字母、数字、下划线 |
\s | 匹配空白字符 |
\S | 匹配非空白字符 |
3.2 量词
表达式 | 说明 |
---|---|
* | 0次或多次 |
+ | 1次或多次 |
? | 0次或1次 |
{n} | 恰好n次 |
{n,} | 至少n次 |
{n,m} | 至少n次,至多m次 |
3.3 位置匹配
表达式 | 说明 |
---|---|
^ | 匹配字符串开始 |
$ | 匹配字符串结束 |
\b | 匹配单词边界 |
\B | 匹配非单词边界 |
3.4 字符类
[aeiou] // 匹配任意一个小写元音字母
[^aeiou] // 匹配任意一个非小写元音字母
[a-zA-Z] // 匹配任意一个字母
[0-9] // 匹配任意一个数字
四、分组和捕获
4.1 基本分组
使用括号()
创建捕获组:
string pattern = @"(\d{4})-(\d{2})-(\d{2})"; // 匹配日期格式YYYY-MM-DD
string input = "Today is 2023-05-15.";
Match match = Regex.Match(input, pattern);
if (match.Success)
{
Console.WriteLine($"Year: {match.Groups[1].Value}"); // 2023
Console.WriteLine($"Month: {match.Groups[2].Value}"); // 05
Console.WriteLine($"Day: {match.Groups[3].Value}"); // 15
}
4.2 命名分组
可以为分组指定名称,提高可读性:
string pattern = @"(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})";
string input = "Today is 2023-05-15.";
Match match = Regex.Match(input, pattern);
if (match.Success)
{
Console.WriteLine($"Year: {match.Groups["year"].Value}"); // 2023
Console.WriteLine($"Month: {match.Groups["month"].Value}"); // 05
Console.WriteLine($"Day: {match.Groups["day"].Value}"); // 15
}
五、替换和分割
5.1 替换字符串
string pattern = @"\d+";
string input = "There are 123 apples and 456 oranges.";
string replacement = "XXX";
string result = Regex.Replace(input, pattern, replacement);
Console.WriteLine(result); // 输出: There are XXX apples and XXX oranges.
5.2 使用匹配内容替换
string pattern = @"(?<number>\d+)";
string input = "123 apples and 456 oranges";
// 将每个数字替换为其平方
string result = Regex.Replace(input, pattern,
m => (int.Parse(m.Groups["number"].Value) * (int.Parse(m.Groups["number"].Value)).ToString());
Console.WriteLine(result); // 输出: 15129 apples and 207936 oranges
5.3 分割字符串
string pattern = @"\s*,\s*"; // 匹配逗号及周围的任意空白
string input = "apple, banana, cherry, date";
string[] substrings = Regex.Split(input, pattern);
foreach (string s in substrings)
{
Console.WriteLine($"'{s}'");
}
// 输出:
// 'apple'
// 'banana'
// 'cherry'
// 'date'
六、常用正则表达式示例
6.1 验证电子邮件
bool IsValidEmail(string email)
{
string pattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
return Regex.IsMatch(email, pattern);
}
Console.WriteLine(IsValidEmail("test@example.com")); // true
Console.WriteLine(IsValidEmail("invalid.email@com")); // false
6.2 验证URL
bool IsValidUrl(string url)
{
string pattern = @"^(https?|ftp)://[^\s/$.?#].[^\s]*$";
return Regex.IsMatch(url, pattern);
}
6.3 提取HTML标签内容
string html = "<div class='content'>Hello <b>World</b></div>";
string pattern = @"<[^>]+>(.*?)</[^>]+>";
MatchCollection matches = Regex.Matches(html, pattern);
foreach (Match m in matches)
{
Console.WriteLine(m.Groups[1].Value);
}
// 输出:
// Hello
// World
6.4 验证密码强度
bool IsStrongPassword(string password)
{
// 至少8个字符,包含大小写字母、数字和特殊字符
string pattern = @"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).{8,}$";
return Regex.IsMatch(password, pattern);
}
七、高级技巧
7.1 非捕获组
使用(?:...)
表示非捕获组,不保存匹配内容:
string pattern = @"(?:Mr|Ms|Mrs)\. (\w+)";
string input = "Mr. Smith and Ms. Johnson";
MatchCollection matches = Regex.Matches(input, pattern);
foreach (Match m in matches)
{
Console.WriteLine(m.Groups[1].Value); // 只捕获名字
}
// 输出:
// Smith
// Johnson
7.2 正向/负向预查
// 正向肯定预查(?=...)
string passwordPattern = @"^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,}$";
// 正向否定预查(?!...)
string noNumbersPattern = @"^(?!.*\d).+$";
// 负向肯定预查(?<=...)
string afterDollarPattern = @"(?<=\$)\d+"; // 匹配$后面的数字
// 负向否定预查(?<!...)
string notAfterDollarPattern = @"(?<!\$)\d+"; // 匹配不在$后面的数字
7.3 贪婪与懒惰匹配
默认情况下,量词是贪婪的(尽可能多匹配),添加?
变为懒惰的(尽可能少匹配):
string input = "<div>content1</div><div>content2</div>";
// 贪婪匹配
string greedyPattern = @"<div>.*</div>";
Match greedyMatch = Regex.Match(input, greedyPattern);
Console.WriteLine(greedyMatch.Value); // 匹配整个字符串
// 懒惰匹配
string lazyPattern = @"<div>.*?</div>";
Match lazyMatch = Regex.Match(input, lazyPattern);
Console.WriteLine(lazyMatch.Value); // 只匹配第一个<div>...</div>
八、性能优化
- 预编译正则表达式:对于频繁使用的正则表达式,使用
RegexOptions.Compiled
- 避免过度回溯:简化正则表达式,避免嵌套量词
- 使用非捕获组:当不需要捕获内容时使用
(?:...)
- 设置超时:防止恶意输入导致长时间匹配
var regex = new Regex(complexPattern,
RegexOptions.Compiled | RegexOptions.IgnoreCase,
TimeSpan.FromSeconds(1)); // 设置1秒超时
九、常见问题与解决方案
9.1 正则表达式不匹配
- 检查特殊字符是否转义
- 确认是否使用了正确的字符类
- 检查大小写敏感性(使用
RegexOptions.IgnoreCase
)
9.2 性能问题
- 简化正则表达式
- 避免使用
.*
这样的宽泛匹配 - 考虑将复杂正则表达式拆分为多个简单正则表达式
9.3 多行匹配
使用RegexOptions.Multiline
使^
和$
匹配每行的开头和结尾:
string input = "Line1\nLine2\nLine3";
string pattern = @"^Line\d$";
MatchCollection matches = Regex.Matches(input, pattern, RegexOptions.Multiline);
十、总结
C#中的正则表达式提供了强大的字符串处理能力。掌握正则表达式可以:
- 高效验证各种格式的字符串
- 灵活提取字符串中的特定内容
- 实现复杂的字符串替换和转换
- 处理各种文本解析任务
记住以下最佳实践:
- 为复杂正则表达式添加注释
- 对用户提供的正则表达式进行安全审查
- 为可能耗时的操作设置超时
- 编写单元测试验证正则表达式行为
通过本教程的学习,您应该能够在C#中熟练使用正则表达式解决各种字符串处理问题。