System.Text.RegularExpressions.Regex 类

本文提供了此 API 参考文档的补充说明。

Regex 表示 。NET 的正则表达式引擎。 可以使用此类来:

  • 快速分析大量文本以查找特定字符模式。
  • 提取、编辑、替换或删除文本子字符串。
  • 将提取的字符串添加到集合以生成报表。

注意

如果要通过确定字符串是否符合特定的正则表达式模式来验证字符串,可以使用该 System.Configuration.RegexStringValidator 类。

若要使用正则表达式,可以使用正则表达式语言中所述 的语法定义要在文本流中标识的模式 - 快速参考。 接下来,可以选择实例化对象 Regex 。 最后,调用执行某些操作的方法,例如替换与正则表达式模式匹配的文本,或标识模式匹配。

有关正则表达式语言的详细信息,请参阅 正则表达式语言 - 快速参考 或下载并打印以下手册之一:

Word 中的快速参考(.docx)格式为 PDF 格式的快速参考(.pdf) 格式

正则表达式与字符串方法

System.String 类包含多个搜索和比较方法,可用于执行与文本的模式匹配。 例如,String.Contains字符串String.StartsWithString.EndsWith实例是否包含指定的子字符串,以及String.IndexOfAnyString.IndexOfString.LastIndexOf方法以及String.LastIndexOfAny方法是否返回字符串中指定子字符串的起始位置。 搜索特定字符串时,请使用类的方法 System.String 。 在字符串中搜索特定模式时, Regex 请使用该类。 有关详细信息和示例,请参阅 .NET 正则表达式

静态与实例方法

定义正则表达式模式后,可以通过以下两种方式之一将其提供给正则表达式引擎:

  • 实例化 Regex 表示正则表达式的对象。 为此,请将正则表达式模式传递给 Regex 构造函数。 对象 Regex 是不可变的;使用正则表达式实例化 Regex 对象时,无法更改该对象的正则表达式。

  • 通过提供正则表达式和文本来搜索 staticShared 在 Visual Basic) Regex 方法中。 这样,便可以在不显式创建 Regex 对象的情况下使用正则表达式。

所有 Regex 模式标识方法都包括静态和实例重载。

正则表达式引擎必须先编译特定模式,然后才能使用该模式。 由于 Regex 对象是不可变的,因此这是在调用类构造函数或静态方法时 Regex 发生的一次性过程。 为了无需重复编译单个正则表达式,正则表达式引擎将缓存静态方法调用中使用的已编译正则表达式。 因此,正则表达式模式匹配方法可为静态和实例方法提供可比的性能。 但是,在以下两种情况下,缓存可能会对性能产生不利影响:

  • 对大量正则表达式使用静态方法调用时。 默认情况下,正则表达式引擎缓存最近使用的 15 个静态正则表达式。 如果应用程序使用超过 15 个静态正则表达式,则必须重新编译一些正则表达式。 若要防止此重新编译,可以增加 Regex.CacheSize 属性。

  • 使用以前编译的正则表达式实例化新 Regex 对象时。 例如,下面的代码定义了一个正则表达式,用于在文本流中查找重复的单词。 尽管该示例使用单个正则表达式,但它实例化一个新 Regex 对象来处理每行文本。 这会导致每次循环迭代时重新编译正则表达式。

    StreamReader sr = new StreamReader(filename);
    string input;
    string pattern = @"\b(\w+)\s\1\b";
    while (sr.Peek() >= 0)
    {
       input = sr.ReadLine();
       Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
       MatchCollection matches = rgx.Matches(input);
       if (matches.Count > 0)
       {
          Console.WriteLine("{0} ({1} matches):", input, matches.Count);
          foreach (Match match in matches)
             Console.WriteLine("   " + match.Value);
       }
    }
    sr.Close();
    
    Dim sr As New StreamReader(filename)
    Dim input As String
    Dim pattern As String = "\b(\w+)\s\1\b"
    Do While sr.Peek() >= 0
       input = sr.ReadLine()
       Dim rgx As New Regex(pattern, RegexOptions.IgnoreCase)
       Dim matches As MatchCollection = rgx.Matches(input)
       If matches.Count > 0 Then
          Console.WriteLine("{0} ({1} matches):", input, matches.Count)
          For Each match As Match In matches
             Console.WriteLine("   " + match.Value)
          Next   
       End If
    Loop
    sr.Close()
    

    若要防止重新编译,应实例化需要它的所有代码可访问的单个 Regex 对象,如以下重写示例所示。

    StreamReader sr = new StreamReader(filename);
    string input;
    string pattern = @"\b(\w+)\s\1\b";
    Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
    
    while (sr.Peek() >= 0)
    {
       input = sr.ReadLine();
       MatchCollection matches = rgx.Matches(input);
       if (matches.Count > 0)
       {
          Console.WriteLine("{0} ({1} matches):", input, matches.Count);
          foreach (Match match in matches)
             Console.WriteLine("   " + match.Value);
       }
    }
    sr.Close();
    
    Dim sr As New StreamReader(filename)
    Dim input As String
    Dim pattern As String = "\b(\w+)\s\1\b"
    Dim rgx As New Regex(pattern, RegexOptions.IgnoreCase)
    Do While sr.Peek() >= 0
       input = sr.ReadLine()
       Dim matches As MatchCollection = rgx.Matches(input)
       If matches.Count > 0 Then
          Console.WriteLine("{0} ({1} matches):", input, matches.Count)
          For Each match As Match In matches
             Console.WriteLine("   " + match.Value)
          Next   
       End If
    Loop
    sr.Close()
    

执行正则表达式操作

无论是决定实例化 Regex 对象并调用其方法还是调用静态方法,该 Regex 类都提供以下模式匹配功能:

  • 匹配项的验证。 IsMatch调用该方法以确定是否存在匹配项。

  • 检索单个匹配项。 调用 Match 该方法以检索表示 Match 字符串或字符串中第一个匹配项的对象。 可以通过调用 Match.NextMatch 该方法来检索后续匹配项。

  • 检索所有匹配项。 调用 Matches 该方法检索一个 System.Text.RegularExpressions.MatchCollection 对象,该对象表示在字符串或字符串的一部分中找到的所有匹配项。

  • 替换匹配的文本。 Replace调用此方法以替换匹配的文本。 替换文本也可以由正则表达式定义。 此外,某些 Replace 方法包括一个 MatchEvaluator 参数,可用于以编程方式定义替换文本。

  • 创建从输入字符串的各个部分构成的字符串数组。 调用 Split 该方法以在正则表达式定义的位置拆分输入字符串。

除了模式匹配方法之外,该 Regex 类还包含多个特殊用途的方法:

  • 该方法 Escape 将转义任何可解释为正则表达式或输入字符串中的正则表达式运算符的字符。
  • 该方法 Unescape 删除这些转义字符。
  • 该方法 CompileToAssembly 创建一个包含预定义正则表达式的程序集。 .NET 包含命名空间中 System.Web.RegularExpressions 这些特殊用途程序集的示例。

定义超时值

.NET 支持功能齐全的正则表达式语言,在模式匹配方面提供强大的功能和灵活性。 但是,电源和灵活性代价是:性能不佳的风险。 执行不佳的正则表达式很容易创建。 在某些情况下,依赖于过度回溯的正则表达式操作在处理几乎与正则表达式模式匹配的文本时,可能会停止响应。 有关 .NET 正则表达式引擎的详细信息,请参阅 正则表达式行为的详细信息。 有关过度回溯的详细信息,请参阅 回溯

从 .NET Framework 4.5 开始,可以为正则表达式匹配定义超时间隔,以限制过度回溯。 根据正则表达式模式和输入文本,执行时间可能超过指定的超时间隔,但它不会花费比指定的超时间隔更多的时间回溯。 如果正则表达式引擎超时,则会引发异常 RegexMatchTimeoutException 。 在大多数情况下,这可以防止正则表达式引擎通过尝试匹配几乎与正则表达式模式匹配的文本来浪费处理能力。 但是,它还可能指示已设置超时间隔太低,或者当前计算机负载导致性能总体下降。

如何处理异常取决于异常的原因。 如果由于超时间隔设置过低或计算机负载过大而发生异常,则可以增加超时间隔并重试匹配操作。 如果由于正则表达式依赖于过度回溯而发生异常,则可以假定匹配不存在,并且(可选)可以记录有助于修改正则表达式模式的信息。

实例化正则表达式对象时,可以通过调用 Regex(String, RegexOptions, TimeSpan) 构造函数来设置超时间隔。 对于静态方法,可以通过调用具有 matchTimeout 参数的匹配方法的重载来设置超时间隔。 如果未显式设置超时值,则按如下所示确定默认超时值:

  • 使用应用程序范围的超时值(如果存在)。 通过调用AppDomain.SetData方法将值的REGEX_DEFAULT_MATCH_TIMEOUT字符串表示形式TimeSpan分配给属性来设置应用程序范围的超时值。
  • 使用值 InfiniteMatchTimeout(如果未设置应用程序范围的超时值)。

重要

建议在所有正则表达式模式匹配操作中设置超时值。 有关详细信息,请参阅 正则表达式的最佳做法。

示例

以下示例使用正则表达式检查字符串中重复出现的单词。 正则表达式 \b(?<word>\w+)\s+(\k<word>)\b 可以解释为下表所示。

模式 说明
\b 在单词边界处启动匹配。
(?<word>\w+) 将一个或多个单词字符与单词边界匹配。 将此捕获组 word命名为 。
\s+ 匹配一个或多个空白字符。
(\k<word>) 匹配已命名 word的捕获组。
\b 与字边界匹配。
using System;
using System.Text.RegularExpressions;

public class Test
{
    public static void Main ()
    {
        // Define a regular expression for repeated words.
        Regex rx = new Regex(@"\b(?<word>\w+)\s+(\k<word>)\b",
          RegexOptions.Compiled | RegexOptions.IgnoreCase);

        // Define a test string.
        string text = "The the quick brown fox  fox jumps over the lazy dog dog.";

        // Find matches.
        MatchCollection matches = rx.Matches(text);

        // Report the number of matches found.
        Console.WriteLine("{0} matches found in:\n   {1}",
                          matches.Count,
                          text);

        // Report on each match.
        foreach (Match match in matches)
        {
            GroupCollection groups = match.Groups;
            Console.WriteLine("'{0}' repeated at positions {1} and {2}",
                              groups["word"].Value,
                              groups[0].Index,
                              groups[1].Index);
        }
    }
}

// The example produces the following output to the console:
//       3 matches found in:
//          The the quick brown fox  fox jumps over the lazy dog dog.
//       'The' repeated at positions 0 and 4
//       'fox' repeated at positions 20 and 25
//       'dog' repeated at positions 49 and 53
Imports System.Text.RegularExpressions

Public Module Test

    Public Sub Main()
        ' Define a regular expression for repeated words.
        Dim rx As New Regex("\b(?<word>\w+)\s+(\k<word>)\b", _
               RegexOptions.Compiled Or RegexOptions.IgnoreCase)

        ' Define a test string.        
        Dim text As String = "The the quick brown fox  fox jumps over the lazy dog dog."
        
        ' Find matches.
        Dim matches As MatchCollection = rx.Matches(text)

        ' Report the number of matches found.
        Console.WriteLine("{0} matches found in:", matches.Count)
        Console.WriteLine("   {0}", text)

        ' Report on each match.
        For Each match As Match In matches
            Dim groups As GroupCollection = match.Groups
            Console.WriteLine("'{0}' repeated at positions {1} and {2}", _ 
                              groups.Item("word").Value, _
                              groups.Item(0).Index, _
                              groups.Item(1).Index)
        Next
    End Sub
End Module
' The example produces the following output to the console:
'       3 matches found in:
'          The the quick brown fox  fox jumps over the lazy dog dog.
'       'The' repeated at positions 0 and 4
'       'fox' repeated at positions 20 and 25
'       'dog' repeated at positions 49 and 53

下一个示例演示如何使用正则表达式来检查字符串是表示货币值还是具有正确的格式来表示货币值。 在这种情况下,正则表达式是从 en-US 区域性的 NumberFormatInfo.CurrencyDecimalSeparatorNumberFormatInfo.CurrencySymbolCurrencyDecimalDigitsNumberFormatInfo.NegativeSignNumberFormatInfo.PositiveSign属性动态生成的。 生成的正则表达式为 ^\s*[\+-]?\s?\$?\s?(\d*\.?\d{2}?){1}$. 此正则表达式可以解释为下表所示。

模式 说明
^ 从字符串的开头开始。
\s* 匹配零个或多个空白字符。
[\+-]? 匹配正号或负号的零个或一个匹配项。
\s? 匹配零个或一个空白字符。
\$? 匹配美元符号的零个或一个匹配项。
\s? 匹配零个或一个空白字符。
\d* 匹配零个或多个十进制数字。
\.? 匹配零个或一个小数点符号。
(\d{2})? 捕获组 1:匹配两个十进制数字零或一次。
(\d*\.?(\d{2})?){1} 匹配由小数点符号分隔的整数和小数位数的模式,至少一次。
$ 匹配字符串的末尾。

在这种情况下,正则表达式假定有效的货币字符串不包含组分隔符,并且它没有小数位数或由指定区域性 CurrencyDecimalDigits 的属性定义的小数位数。

using System;
using System.Globalization;
using System.Text.RegularExpressions;

public class Example
{
    public static void Main()
    {
        // Get the en-US NumberFormatInfo object to build the regular 
        // expression pattern dynamically.
        NumberFormatInfo nfi = CultureInfo.GetCultureInfo("en-US").NumberFormat;

        // Define the regular expression pattern.
        string pattern;
        pattern = @"^\s*[";
        // Get the positive and negative sign symbols.
        pattern += Regex.Escape(nfi.PositiveSign + nfi.NegativeSign) + @"]?\s?";
        // Get the currency symbol.
        pattern += Regex.Escape(nfi.CurrencySymbol) + @"?\s?";
        // Add integral digits to the pattern.
        pattern += @"(\d*";
        // Add the decimal separator.
        pattern += Regex.Escape(nfi.CurrencyDecimalSeparator) + "?";
        // Add the fractional digits.
        pattern += @"(\d{";
        // Determine the number of fractional digits in currency values.
        pattern += nfi.CurrencyDecimalDigits.ToString() + "})?){1}$";

        Console.WriteLine($"Pattern is {pattern}\n");

        Regex rgx = new Regex(pattern);

        // Define some test strings.
        string[] tests = { "-42", "19.99", "0.001", "100 USD",
                         ".34", "0.34", "1,052.21", "$10.62",
                         "+1.43", "-$0.23" };

        // Check each test string against the regular expression.
        foreach (string test in tests)
        {
            if (rgx.IsMatch(test))
                Console.WriteLine($"{test} is a currency value.");
            else
                Console.WriteLine($"{test} is not a currency value.");
        }
    }
}
// The example displays the following output:
//       Pattern is ^\s*[\+-]?\s?\$?\s?(\d*\.?(\d{2})?){1}$
//
//       -42 is a currency value.
//       19.99 is a currency value.
//       0.001 is not a currency value.
//       100 USD is not a currency value.
//       .34 is a currency value.
//       0.34 is a currency value.
//       1,052.21 is not a currency value.
//       $10.62 is a currency value.
//       +1.43 is a currency value.
//       -$0.23 is a currency value.
Imports System.Globalization
Imports System.Text.RegularExpressions

Public Module Example
   Public Sub Main()
      ' Get the current NumberFormatInfo object to build the regular 
      ' expression pattern dynamically.
      Dim nfi As NumberFormatInfo = CultureInfo.GetCultureInfo("en-US").NumberFormat

      ' Define the regular expression pattern.
      Dim pattern As String 
      pattern = "^\s*["
      ' Get the positive and negative sign symbols.
      pattern += Regex.Escape(nfi.PositiveSign + nfi.NegativeSign) + "]?\s?"
      ' Get the currency symbol.
      pattern += Regex.Escape(nfi.CurrencySymbol) + "?\s?"
      ' Add integral digits to the pattern.
      pattern += "(\d*"
      ' Add the decimal separator.
      pattern += Regex.Escape(nfi.CurrencyDecimalSeparator) + "?"
      ' Add the fractional digits.
      pattern += "(\d{"
      ' Determine the number of fractional digits in currency values.
      pattern += nfi.CurrencyDecimalDigits.ToString() + "})?){1}$"
      
      Console.WriteLine("Pattern is {0}", pattern)
      Console.WriteLine()
      
      Dim rgx As New Regex(pattern)

      ' Define some test strings.
      Dim tests() As String = {"-42", "19.99", "0.001", "100 USD", _
                               ".34", "0.34", "1,052.21", "$10.62", _
                               "+1.43", "-$0.23" }

      ' Check each test string against the regular expression.
      For Each test As String In tests
         If rgx.IsMatch(test) Then
            Console.WriteLine("{0} is a currency value.", test)
         Else
            Console.WriteLine("{0} is not a currency value.", test)
         End If
      Next
   End Sub
End Module
' The example displays the following output:
'       Pattern is ^\s*[\+-]?\s?\$?\s?(\d*\.?(\d{2})?){1}$
'
'       -42 is a currency value.
'       19.99 is a currency value.
'       0.001 is not a currency value.
'       100 USD is not a currency value.
'       .34 is a currency value.
'       0.34 is a currency value.
'       1,052.21 is not a currency value.
'       $10.62 is a currency value.
'       +1.43 is a currency value.
'       -$0.23 is a currency value.

由于此示例中的正则表达式是动态生成的,因此在设计时,你不知道指定区域性的货币符号、小数符号还是指定区域性的正数和负号(在本示例中的 en-US)可能被正则表达式引擎错误地解释为正则表达式语言运算符。 为了防止任何错误解释,该示例将每个动态生成的字符串传递给 Escape 该方法。