在 C# 中使用正则表达式

如果您需要复习正则表达式的使用方法,请先查看我们的 交互式教程

C# 通过标准 .NET 框架中 System.Text.RegularExpressions 命名空间中的类来支持正则表达式。虽然 .NET 正则表达式库支持的一些高级功能与 PCRE 存在一些差异,但它们都共享大部分语法,并且表达式可以在 C# 和其他语言中使用。

在下面的示例中,如果您尝试运行代码,请确保在源文件顶部导入以下命名空间

using System.Text.RegularExpressions;

逐字字符串字面量

在 C# 中编写正则表达式时,建议使用 逐字字符串 而不是普通字符串。逐字字符串以特殊前缀 (@) 开头,并指示 C# 不要解释字符串中的反斜杠和特殊元字符,从而允许您将它们直接传递给正则表达式引擎。

这意味着像 "\n\w" 这样的模式不会被解释,并且可以写成 @"\n\w" 而不是像其他语言中的 "\\n\\w",这更容易阅读。

匹配字符串

System.Text.RegularExpressions 命名空间中有一个 Regex 类,它封装了正则表达式引擎的接口,并允许您使用正则表达式执行匹配并从文本中提取信息。

要测试正则表达式是否匹配字符串,可以使用静态方法 Regex.Match(),它接受一组可选的 RegexOptions 枚举。这将返回一个 Match 对象,其中包含有关匹配(如果有)在何处找到的信息。

方法
Match match = Regex.Match(InputStr, Pattern, RegexOptions)
示例
// 让我们使用正则表达式来匹配日期字符串。 string pattern = @"([a-zA-Z]+) (\d+)"; // 对于此调用,RegexOptions 是可选的,我们将在下面详细介绍 // 它们。 Match result = Regex.Match("June 24", pattern); if (result.Success) { // 的确,表达式 "([a-zA-Z]+) (\d+)" 匹配日期字符串 // 要获取匹配的索引,您可以读取 Match 对象的 // Index 和 Length 值。 // 这将打印 [0, 7],因为它匹配字符串的开头和结尾 // 字符串 Console.WriteLine("Match at index [{0}, {1})", result.Index, result.Index + result.Length); // 要获取完全匹配的文本,您可以读取 Match 对象的值 // 这将打印“June 24” Console.WriteLine("Match: {0}", result.Value); // 如果您想遍历每个匹配项,可以调用 // Match 对象的 NextMatch() 方法,它将返回下一个 Match // 对象。 // 这将按顺序打印出每个匹配项。 while (result.Success) { Console.WriteLine("Match: {0}", result.Value); result = result.NextMatch(); } }

捕获组

如果我们想要对整个输入字符串执行全局搜索并返回所有匹配项及其对应的捕获数据,我们可以使用静态方法 Regex.Matches() 获取一个 MatchCollection,可以在上面示例中对其进行迭代和处理。

方法
MatchCollection matches = Regex.Matches(InputStr, Pattern, RegexOptions)
示例
// 让我们使用正则表达式从一些日期字符串中捕获数据。 string pattern = @"([a-zA-Z]+) (\d+)"; MatchCollection matches = Regex.Matches("June 24, August 9, Dec 12", pattern); // 这将打印匹配项的数量 Console.WriteLine("{0} matches", matches.Count); // 这将打印每个匹配项以及输入字符串中的索引 // 匹配项所在的位置: // June 24 at index [0, 7) // August 9 at index [9, 17) // Dec 12 at index [19, 25) foreach (Match match in matches) { Console.WriteLine("Match: {0} at index [{1}, {2})", match.Value, match.Index, match.Index + match.Length); } // 对于每个匹配项,我们可以通过读取 // 捕获的组来提取捕获的信息。 foreach (Match match in matches) { GroupCollection data = match.Groups; // 这将打印此匹配项中捕获的组数 Console.WriteLine("{0} groups captured in {1}", data.Count, match.Value); // 这将打印每个匹配项的月份和日期。请记住, // 第一个组始终是整个匹配文本,因此月份从 // 索引 1 开始。 Console.WriteLine("Month: " + data[1] + ", Day: " + data[2]); // 集合中的每个组也具有 Index 和 Length 成员, // 其中存储了在输入字符串中找到该组的位置。 Console.WriteLine("Month found at[{0}, {1})", data[1].Index, data[1].Index + data[1].Length); }

查找和替换字符串

另一个常见任务是使用正则表达式查找和替换字符串的一部分,例如,替换旧电子邮件域的所有实例,或交换某些文本的顺序。您可以在 C# 中使用静态方法 Regex.Replace() 执行此操作。

替换字符串可以是包含对模式中捕获组的引用的正则表达式,也可以是普通字符串。

方法
string replaced = Regex.Replace(InputStr, Pattern, ReplacementPattern, RegexOption)
示例
// 让我们尝试反转一些日期字符串中日期和月份的顺序 // 字符串。请注意,替换字符串也包含元字符 // (对捕获组的反向引用),因此我们也为此使用逐字 // 字符串。 string pattern = @"([a-zA-Z]+) (\d+)"; // 这将在内联重新排序字符串并打印: // 24 of June, 9 of August, 12 of Dec // 请记住,第一个组始终是完整的匹配文本,因此 // 月份和日期索引从 1 开始而不是零。 string replacedString = Regex.Replace("June 24, August 9, Dec 12", pattern, @"$2 of $1"); Console.WriteLine(replacedString);

RegexOptions 枚举

在上面的正则表达式方法中,您会注意到它们中的每一个也接受一个可选的 RegexOptions 参数。大多数可用标志都是一种便利,可以直接写入正则表达式本身,但在某些情况下,一些标志可能很有用。

  • RegexOptions.Compiled 通过允许正则表达式引擎首先编译模式来加快使用相同模式匹配多个输入字符串的速度。如果未设置任何选项,则默认启用。
  • RegexOptions.IgnoreCase 使模式不区分大小写,以便它匹配不同大小写的字符串
  • RegexOptions.Multiline 在您的输入字符串包含换行符 (\n) 时是必要的,并允许开始和结束元字符 (^$ 分别) 在每行的开头和结尾匹配,而不是在整个输入字符串的开头和结尾匹配
  • RegexOptions.RightToLeft 用于匹配 RTL 语言
  • RegexOptions.Singleline 允许点 (.) 元字符匹配所有字符,包括换行符 (\n)

编译模式以提高性能

虽然上面的静态方法适用于普通处理,但如果您要针对同一模式测试数百万个输入字符串,则可以通过在构造函数中使用模式实例化 Regex 对象来减少对象分配并获得更快的性能。

使用此Regex对象,上面所有相同的方法都可用于该对象,但您无需在每次调用时都再次传入模式。

有关更多信息,您可以阅读MSDN上关于静态方法与实例方法的文档。

链接

有关在C#中使用正则表达式的更多信息,请访问以下链接