• 匹配输入字符串中重复的子表达式。
  • 将限定符应用于拥有多个正则表达式语言元素的子表达式。 有关限定符的更多信息,请参见 Quantifiers
  • 包括由 Regex.Replace Match.Result 方法返回的字符串中的子表达式。
  • Match.Groups 属性中检索各个子表达式,并分别从匹配的文本作为一个整体处理它们。
  • 下表列出了 .NET 正则表达式引擎支持的分组构造,并指示它们是捕获构造还是非捕获构造。

    捕获或非捕获 subexpression )

    此处,子表达式是任何有效的正则表达式模式。 使用括号的捕获按正则表达式中左括号的顺序,从 1 开始,从左到右自动编号。 但是, 命名的捕获组 总是在非命名捕获组之后最后排序。 编号为零的捕获是与整个正则表达式模式匹配的文本。

    默认情况下, ( 子表达式 ) 语言元素捕获匹配的子表达式。 不过,如果正则表达式模式匹配方法的 RegexOptions 参数包含 RegexOptions.ExplicitCapture 标志,或者如果 n 选项应用于此子表达式(请参阅本文稍后将介绍的 组选项 ),就不会捕获匹配的子表达式。

    可以四种方法访问捕获的组:

  • 通过使用正则表达式中的反向引用构造。 使用语法 \ 数字 在同一正则表达式中引用匹配的子表达式,其中 数字 是捕获的表达式的初始数字。

  • 通过使用正则表达式中的命名的反向引用构造。 使用语法 \k< name > 在同一正则表达式中引用匹配的子表达式,其中 name 是捕获组的名称,或使用 \k< 数字 > 在同一正则表达式中引用匹配的子表达式,其中 数字 是捕获组的初始数字。 捕获组具有与其原始编号相同的默认名称。 有关更多信息,请参见本主题后面的 命名匹配的子表达式

  • 通过使用 $ 数字 $ Regex.Replace number Match.Result 替换序列,其中 数字 是捕获的表达式的初始数字。

  • 以编程的方式,通过使用 GroupCollection 对象的方式,该对象由 Match.Groups 属性返回。 集合中位置零上的成员表示正则表达式匹配。 每个后续成员表示匹配的子表达式。 有关更多信息,请参见 分组构造和正则表达式对象 一节。

    以下示例阐释表示文本中重复单词的正则表达式。 正则表达式模式的两个捕获组表示重复的单词的两个实例。 捕获第二个实例,以报告它在输入字符串的起始位置。

    using System;
    using System.Text.RegularExpressions;
    public class Example
       public static void Main()
          string pattern = @"(\w+)\s(\1)\W";
          string input = "He said that that was the the correct answer.";
          foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
             Console.WriteLine("Duplicate '{0}' found at positions {1} and {2}.",
                               match.Groups[1].Value, match.Groups[1].Index, match.Groups[2].Index);
    // The example displays the following output:
    //       Duplicate 'that' found at positions 8 and 13.
    //       Duplicate 'the' found at positions 22 and 26.
    
    Imports System.Text.RegularExpressions
    Module Example
        Public Sub Main()
            Dim pattern As String = "(\w+)\s(\1)\W"
            Dim input As String = "He said that that was the the correct answer."
            For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
                Console.WriteLine("Duplicate '{0}' found at positions {1} and {2}.", _
                                  match.Groups(1).Value, match.Groups(1).Index, match.Groups(2).Index)
        End Sub
    End Module
    ' The example displays the following output:
    '       Duplicate 'that' found at positions 8 and 13.
    '       Duplicate 'the' found at positions 22 and 26.
    

    正则表达式模式为:

    (\w+)\s(\1)\W

    下表演示了如何解释正则表达式模式。

    如果正则表达式模式匹配方法的 RegexOptions 参数包含 RegexOptions.ExplicitCapture 标志,或者如果 n 选项应用于此子表达式(参见本主题后面的 组选项 ),则捕获子表达式的唯一方法就是显式命名捕获组。

    可用以下方式访问已命名的捕获组:

  • 通过使用正则表达式中的命名的反向引用构造。 使用语法 \k<name>在同一正则表达式中引用匹配的子表达式,其中 name 是捕获子表达式的名称。

  • 通过使用正则表达式中的反向引用构造。 使用语法 \数字在同一正则表达式中引用匹配的子表达式,其中 数字 是捕获的表达式的初始数字。 已命名的匹配子表达式在匹配子表达式后从左到右连续编号。

  • 通过使用 ${name} $ Regex.Replace number Match.Result 替换序列,其中 name 是捕获子表达式的名称。

  • 通过在 Regex.ReplaceMatch.Result 方法调用中使用 $数字 替换序列,其中“数字”为捕获的子表达式的序号。

  • 以编程的方式,通过使用 GroupCollection 对象的方式,该对象由 Match.Groups 属性返回。 集合中位置零上的成员表示正则表达式匹配。 每个后续成员表示匹配的子表达式。 已命名的捕获组在集合中存储在已编号的捕获组后面。

  • 以编程方式,通过将子表达式名称提供至 GroupCollection 对象的索引器(在 C# 中),或者提供至其 Item[] 属性(在 Visual Basic 中)。

    简单的正则表达式模式会阐释如何编号(未命名),并且可以以编程方式或通过正则表达式语言语法引用已命名的组。 正则表达式 ((?<One>abc)\d+)?(?<Two>xyz)(.*) 按编号和名称产生下列捕获组。 编号为 0 的第一个捕获组总是指整个模式。 (命名的组总是最后排序。)

    下面的示例阐释了一个正则表达式,标识出重复的单词和紧随每个重复的单词的单词。 正则表达式模式定义两个命名的子表达式:duplicateWordnextWord,前者表示重复的单词,后者表示后面跟随重复单词的单词。

    using System;
    using System.Text.RegularExpressions;
    public class Example
       public static void Main()
          string pattern = @"(?<duplicateWord>\w+)\s\k<duplicateWord>\W(?<nextWord>\w+)";
          string input = "He said that that was the the correct answer.";
          foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
             Console.WriteLine("A duplicate '{0}' at position {1} is followed by '{2}'.",
                               match.Groups["duplicateWord"].Value, match.Groups["duplicateWord"].Index,
                               match.Groups["nextWord"].Value);
    // The example displays the following output:
    //       A duplicate 'that' at position 8 is followed by 'was'.
    //       A duplicate 'the' at position 22 is followed by 'correct'.
    
    Imports System.Text.RegularExpressions
    Module Example
        Public Sub Main()
            Dim pattern As String = "(?<duplicateWord>\w+)\s\k<duplicateWord>\W(?<nextWord>\w+)"
            Dim input As String = "He said that that was the the correct answer."
            Console.WriteLine(Regex.Matches(input, pattern, RegexOptions.IgnoreCase).Count)
            For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
                Console.WriteLine("A duplicate '{0}' at position {1} is followed by '{2}'.", _
                                  match.Groups("duplicateWord").Value, match.Groups("duplicateWord").Index, _
                                  match.Groups("nextWord").Value)
        End Sub
    End Module
    ' The example displays the following output:
    '    A duplicate 'that' at position 8 is followed by 'was'.
    '    A duplicate 'the' at position 22 is followed by 'correct'.
    

    正则表达式模式按如下方式定义:

    (?<duplicateWord>\w+)\s\k<duplicateWord>\W(?<nextWord>\w+)

    下表演示了正则表达式的含义。

    可在正则表达式中重复组名。 例如,可将多个组命名为 digit,如下面的示例所示。 在名称重复的情况下, Group 对象的值由输入字符串中最后一个成功的捕获确定。 此外,如果组名不重复,则使用有关每个捕获的信息填充 CaptureCollection

    在下面的示例中,正则表达式 \D+(?<digit>\d+)\D+(?<digit>\d+)? 中两次出现了名为 digit的组。 第一个名为 digit 的组捕获一个或多个数字字符。 第二个名为 digit 的组捕获一个或多个数字字符的零个或一个匹配项。 如示例的输出所示,如果第二个捕获组成功匹配文本,则文本的值定义 Group 对象的值。 如果第二个捕获组与输入字符串不匹配,则最后一个成功匹配的值定义 Group 对象的值。

    using System;
    using System.Text.RegularExpressions;
    public class Example
       public static void Main()
          String pattern = @"\D+(?<digit>\d+)\D+(?<digit>\d+)?";
          String[] inputs = { "abc123def456", "abc123def" };
          foreach (var input in inputs) {
             Match m = Regex.Match(input, pattern);
             if (m.Success) {
                Console.WriteLine("Match: {0}", m.Value);
                for (int grpCtr = 1; grpCtr < m.Groups.Count; grpCtr++) {
                   Group grp = m.Groups[grpCtr];
                   Console.WriteLine("Group {0}: {1}", grpCtr, grp.Value);
                   for (int capCtr = 0; capCtr < grp.Captures.Count; capCtr++)
                      Console.WriteLine("   Capture {0}: {1}", capCtr,
                                        grp.Captures[capCtr].Value);
             else {
                Console.WriteLine("The match failed.");
             Console.WriteLine();
    // The example displays the following output:
    //       Match: abc123def456
    //       Group 1: 456
    //          Capture 0: 123
    //          Capture 1: 456
    //       Match: abc123def
    //       Group 1: 123
    //          Capture 0: 123
    
    Imports System.Text.RegularExpressions
    Module Example
        Public Sub Main()
            Dim pattern As String = "\D+(?<digit>\d+)\D+(?<digit>\d+)?"
            Dim inputs() As String = {"abc123def456", "abc123def"}
            For Each input As String In inputs
                Dim m As Match = Regex.Match(input, pattern)
                If m.Success Then
                    Console.WriteLine("Match: {0}", m.Value)
                    For grpCtr As Integer = 1 to m.Groups.Count - 1
                        Dim grp As Group = m.Groups(grpCtr)
                        Console.WriteLine("Group {0}: {1}", grpCtr, grp.Value)
                        For capCtr As Integer = 0 To grp.Captures.Count - 1
                            Console.WriteLine("   Capture {0}: {1}", capCtr,
                                              grp.Captures(capCtr).Value)
                    Console.WriteLine("The match failed.")
                End If
                Console.WriteLine()
        End Sub
    End Module
    ' The example displays the following output:
    '       Match: abc123def456
    '       Group 1: 456
    '          Capture 0: 123
    '          Capture 1: 456
    '       Match: abc123def
    '       Group 1: 123
    '          Capture 0: 123
    

    下表演示了正则表达式的含义。

    平衡组定义

    平衡组定义将删除以前定义的组和存储的定义,并在当前组中存储以前定义的组和当前组之间的间隔。 此分组构造具有以下格式:

    (?<name1-name2>subexpression)

    (?'name1-name2' subexpression)

    此处,name1 是当前的组(可选),name2 是以前定义的组,而子表达式是任何有效的正则表达式模式。 平衡组定义删除 name2 的定义并在 name1 中保存 name2name1之间的间隔。 如果未定义 name2 组,则匹配将回溯。 由于删除 name2 的最后一个定义会显示 name2以前的定义,因此该构造允许将 name2 组的捕获堆栈用作计数器,用于跟踪嵌套构造(如括号或者左括号和右括号)。

    平衡组定义将 name2 作为堆栈使用。 将每个嵌套构造的开头字符放在组中,并放在其 Group.Captures 集合中。 当匹配结束字符时,从组中删除其相应的开始字符,并且 Captures 集合减少 1。 所有嵌套构造的开始和结束字符匹配完后,name2 为空。

    通过修改下面示例中的正则表达式来使用合适的嵌套构造的开始和结束字符后,你可以用它来处理多数嵌套构造,如数学表达式或包括多个嵌套方法调用的程序代码行。

    下面的示例使用平衡组定义匹配输入字符串中的左右尖括号 (<>)。 该示例定义两个已命名的组, OpenClose,用作堆栈来跟踪配对的尖括号。 将每个已捕获的左尖括号推入到 Open 组的捕获集合,而将每个已捕获的右尖括号推入到 Close 组的捕获集合。 平衡组定义确保每个左尖括号都有一个匹配的右尖角括号。 如果没有,则仅会在 (?(Open)(?!))组不为空的情况下计算最终子模式 Open 的值(因此,如果所有嵌套构造尚未关闭)。 如果计算了最终子模式的值,则匹配将失败,因为 (?!) 子模式是始终失败的零宽度负预测先行断言。

    using System;
    using System.Text.RegularExpressions;
    class Example
       public static void Main()
          string pattern = "^[^<>]*" +
                           "(" +
                           "((?'Open'<)[^<>]*)+" +
                           "((?'Close-Open'>)[^<>]*)+" +
                           ")*" +
                           "(?(Open)(?!))$";
          string input = "<abc><mno<xyz>>";
          Match m = Regex.Match(input, pattern);
          if (m.Success == true)
             Console.WriteLine("Input: \"{0}\" \nMatch: \"{1}\"", input, m);
             int grpCtr = 0;
             foreach (Group grp in m.Groups)
                Console.WriteLine("   Group {0}: {1}", grpCtr, grp.Value);
                grpCtr++;
                int capCtr = 0;
                foreach (Capture cap in grp.Captures)
                    Console.WriteLine("      Capture {0}: {1}", capCtr, cap.Value);
                    capCtr++;
             Console.WriteLine("Match failed.");
    // The example displays the following output:
    //    Input: "<abc><mno<xyz>>"
    //    Match: "<abc><mno<xyz>>"
    //       Group 0: <abc><mno<xyz>>
    //          Capture 0: <abc><mno<xyz>>
    //       Group 1: <mno<xyz>>
    //          Capture 0: <abc>
    //          Capture 1: <mno<xyz>>
    //       Group 2: <xyz
    //          Capture 0: <abc
    //          Capture 1: <mno
    //          Capture 2: <xyz
    //       Group 3: >
    //          Capture 0: >
    //          Capture 1: >
    //          Capture 2: >
    //       Group 4:
    //       Group 5: mno<xyz>
    //          Capture 0: abc
    //          Capture 1: xyz
    //          Capture 2: mno<xyz>
    
    Imports System.Text.RegularExpressions
    Module Example
        Public Sub Main()
            Dim pattern As String = "^[^<>]*" & _
                                    "(" + "((?'Open'<)[^<>]*)+" & _
                                    "((?'Close-Open'>)[^<>]*)+" + ")*" & _
                                    "(?(Open)(?!))$"
            Dim input As String = "<abc><mno<xyz>>"
            Dim rgx AS New Regex(pattern) '
            Dim m As Match = Regex.Match(input, pattern)
            If m.Success Then
                Console.WriteLine("Input: ""{0}"" " & vbCrLf & "Match: ""{1}""", _
                                   input, m)
                Dim grpCtr As Integer = 0
                For Each grp As Group In m.Groups
                    Console.WriteLine("   Group {0}: {1}", grpCtr, grp.Value)
                    grpCtr += 1
                    Dim capCtr As Integer = 0
                    For Each cap As Capture In grp.Captures
                        Console.WriteLine("      Capture {0}: {1}", capCtr, cap.Value)
                        capCtr += 1
                Console.WriteLine("Match failed.")
            End If
        End Sub
    End Module
    ' The example displays the following output:
    '       Input: "<abc><mno<xyz>>"
    '       Match: "<abc><mno<xyz>>"
    '          Group 0: <abc><mno<xyz>>
    '             Capture 0: <abc><mno<xyz>>
    '          Group 1: <mno<xyz>>
    '             Capture 0: <abc>
    '             Capture 1: <mno<xyz>>
    '          Group 2: <xyz
    '             Capture 0: <abc
    '             Capture 1: <mno
    '             Capture 2: <xyz
    '          Group 3: >
    '             Capture 0: >
    '             Capture 1: >
    '             Capture 2: >
    '          Group 4:
    '          Group 5: mno<xyz>
    '             Capture 0: abc
    '             Capture 1: xyz
    '             Capture 2: mno<xyz>
    

    正则表达式模式为:

    ^[^<>]*(((?'Open'<)[^<>]*)+((?'Close-Open'>)[^<>]*)+)*(?(Open)(?!))$

    正则表达式按如下方式解释:

    ((?'Close-Open'>)[^<>]*)+ 匹配跟在零后面或跟在非左尖括号或非右尖括号的多个字符后面的一个或多个右尖括号匹配项。 在匹配右尖括号时,将 Open 组和当前组分配给 Close 组并删除 Open 组的定义。 这是第三个捕获组。 (((?'Open'<)[^<>]*)+((?'Close-Open'>)[^<>]*)+)* 匹配零个或多个下列模式的匹配项:一个或多个左尖括号匹配项,后跟零个或多个非尖括号字符,后跟一个或多个右尖括号的匹配项,后跟零个或多个非尖括号的匹配项。 在匹配右尖括号时,删除 Open 组的定义,并将 Open 组和当前组之间的子字符串分配给 Close 组。 这是第一个捕获组。 (?(Open)(?!)) 如果 Open 组存在,并可以匹配空字符串,则放弃匹配,但不前移字符串中的正则表达式引擎的位置。 这是零宽度负预测先行断言。 因为空字符串总是隐式地存在于输入字符串中,所以此匹配始终失败。 此匹配的失败表示尖括号不平衡。 匹配输入字符串的末尾部分。

    最终子表达式 (?(Open)(?!)),指示是否正确平衡输入字符串中的嵌套构造(例如,是否每个左尖括号由右键括号匹配)。 它使用基于有效的捕获组的条件匹配,有关详细信息请参阅 替换构造。 如果定义了 Open 组,则正则表达式引擎会尝试匹配输入字符串中的子表达式 (?!) 。 仅当嵌套构造不均衡时,才应该定义 Open 组。 因此,要在输入字符串中匹配的模式应该是一个始终导致匹配失败的模式。 在此情况下,(?!) 是始终失败的零宽度负预测先行断言,因为空字符串总是隐式地存在于输入字符串中的下一个位置。

    在此示例中,正则表达式引擎计算输入字符串“<abc><mno<xyz>>”,如下表所示。

    ((?'Close-Open'>) 匹配“<abc>”中的右尖括号,将“abc”(Open 组和右尖括号之间的子字符串)分配给 Close 组,并删除 Open 组的当前值(“<”),同时保持它为空。 [^<>]* 查找右尖括号之后的非尖括号字符;未找到匹配项。 第三个捕获组的值是“>”。

    输入字符串中的下一个字符不是右尖括号,因此正则表达式引擎不会循环回到 ((?'Close-Open'>)[^<>]*) 子模式。 第一个捕获组的值是“<abc>”。

    输入字符串中的下一个字符是左尖括号,因此正则表达式引擎会循环回到 (((?'Open'<) 子模式。 (((?'Open'<) 匹配“<mno”中的左尖括号,并将它分配给 Open 组。 其 Group.Captures 集合现在具有单个值“<”。 [^<>]* 与“mno”匹配。 “<mno”是第二个捕获组的值。

    输入字符串中的下一个字符是左尖括号,因此正则表达式引擎会循环回到 (?'Open'<)[^<>]*) 子模式。 (((?'Open'<) 匹配“<xyz>”中的左尖括号,并将它分配给 Open 组。 Open 组的 Group.Captures 集合现在包括两个捕获:“<mno”中的左尖括号和“<xyz>”中的左尖括号。 [^<>]* 与“xyz”匹配。 “<xyz”是第二个捕获组的值。

    输入字符串中的下一个字符不是左尖括号,因此正则表达式引擎不会循环回到 (?'Open'<)[^<>]*) 子模式。 ((?'Close-Open'>) 匹配“<xyz>”中的右尖括号。 “xyz”将 Open 组合右尖括号之间的子字符串分配给 Close 组,并删除 Open 组的当前值。 前一个捕获的值(“<mno”中的左尖括号)成为 Open 组的当前值。 Open 组的 Captures 集合现在包括一个捕获,即“<xyz>”中的左尖括号。 [^<>]* 查找非尖括号字符;未找到匹配项。 第三个捕获组的值是“>”。

    输入字符串中的下一个字符是右尖括号,因此正则表达式引擎会循环回到 ((?'Close-Open'>)[^<>]*) 子模式。 ((?'Close-Open'>) 匹配“xyz>>”中的最后一个右尖括号,将“mno<xyz>”(Open 组和右尖括号之间的子字符串)分配给 Close 组,并删除 Open 组的当前值。 Open 组现在为空。 [^<>]* 查找非尖括号字符;未找到匹配项。 第三个捕获组的值是“>”。

    输入字符串中的下一个字符不是右尖括号,因此正则表达式引擎不会循环回到 ((?'Close-Open'>)[^<>]*) 子模式。 第一个捕获组的值是“<mno<xyz>>”。

    输入字符串中的下一个字符不是左尖括号,因此正则表达式引擎不会循环回到 (((?'Open'<) 子模式。 (?(Open)(?!)) Open 组是未定义的,因此没有尝试匹配。 匹配输入字符串的末尾部分。

    以下分组构造不会捕获与子表达式匹配的子字符串:

    (?:subexpression)

    此处,子表达式是任何有效的正则表达式模式。 当一个限定符应用到一个组,但组捕获的子字符串并非所需时,通常会使用非捕获组构造。

    如果正则表达式包含嵌套的分组构造,则外部非捕获组构造不适用于内部嵌套组构造。

    下面的示例阐释包括非捕获组的正则表达式。 请注意输出不包含任何已捕获的组。

    using System;
    using System.Text.RegularExpressions;
    public class Example
       public static void Main()
          string pattern = @"(?:\b(?:\w+)\W*)+\.";
          string input = "This is a short sentence.";
          Match match = Regex.Match(input, pattern);
          Console.WriteLine("Match: {0}", match.Value);
          for (int ctr = 1; ctr < match.Groups.Count; ctr++)
             Console.WriteLine("   Group {0}: {1}", ctr, match.Groups[ctr].Value);
    // The example displays the following output:
    //       Match: This is a short sentence.
    
    Imports System.Text.RegularExpressions
    Module Example
        Public Sub Main()
            Dim pattern As String = "(?:\b(?:\w+)\W*)+\."
            Dim input As String = "This is a short sentence."
            Dim match As Match = Regex.Match(input, pattern)
            Console.WriteLine("Match: {0}", match.Value)
            For ctr As Integer = 1 To match.Groups.Count - 1
                Console.WriteLine("   Group {0}: {1}", ctr, match.Groups(ctr).Value)
        End Sub
    End Module
    ' The example displays the following output:
    '       Match: This is a short sentence.
    

    正则表达式 (?:\b(?:\w+)\W*)+\. 匹配由句号终止的语句。 因为正则表达式重点介绍句子,而不是个别单词,所以分组构造以独占方式用作限定符。 正则表达式模式可以解释为下表中所示内容。

    (?imnsx-imnsx: subexpression)

    此处,子表达式是任何有效的正则表达式模式。 例如, (?i-s:) 将打开不区分大小写并禁用单行模式。 有关可以指定的内联选项的更多信息,请参见 正则表达式选项

    可以指定将应用于整个正则表达式,而不是子表达式的选项,方法是使用 System.Text.RegularExpressions.Regex 类构造函数或静态方法。 也可指定在正则表达式特定点后使用的内联选项,方法是使用 (?imnsx-imnsx) 语言构造。

    组的选项构造并非捕获组。 即尽管 子表达式 捕获的字符串的任意部分包含在匹配中,但不会包含在捕获的组中也不会用于填充 GroupCollection 对象。

    例如,以下示例中的正则表达式 \b(?ix: d \w+)\s 使用分组构造中的内联选项,以启用不区分大小写的匹配和在识别所有以字母“d”开头的单词时忽略模式空白。 该正则表达式的定义如下表所示。

    string input = "Dogs are decidedly good pets."; foreach (Match match in Regex.Matches(input, pattern)) Console.WriteLine("'{0}// found at index {1}.", match.Value, match.Index); // The example displays the following output: // 'Dogs // found at index 0. // 'decidedly // found at index 9.
    Dim pattern As String = "\b(?ix: d \w+)\s"
    Dim input As String = "Dogs are decidedly good pets."
    For Each match As Match In Regex.Matches(input, pattern)
        Console.WriteLine("'{0}' found at index {1}.", match.Value, match.Index)
    ' The example displays the following output:
    '    'Dogs ' found at index 0.
    '    'decidedly ' found at index 9.      
    

    零宽度正预测先行断言

    以下分组构造定义零宽度正预测先行断言:

    subexpression)

    此处,子表达式为任何正则表达式模式。 若要成功匹配,则输入字符串必须匹配 子表达式中的正则表达式模式,尽管匹配的子字符串未包含在匹配结果中。 零宽度正预测先行断言不会回溯。

    通常,零宽度正预测先行断言是在正则表达式模式的末尾找到的。 它定义了一个子字符串,该子字符串必须出现在匹配字符串的末尾但又不能包含在匹配结果中。 还有助于防止过度回溯。 可使用零宽度正预测先行断言来确保特定捕获组以与专为该捕获组定义的模式的子集相匹配的文本开始。 例如,如果捕获组与连续单词字符相匹配,可以使用零宽度正预测先行断言要求第一个字符是按字母顺序排列的大写字符。

    下面的示例使用零宽度正预测先行断言,以匹配输入字符串中谓词“is”前的单词。

    using System;
    using System.Text.RegularExpressions;
    public class Example
       public static void Main()
          string pattern = @"\b\w+(?=\sis\b)";
          string[] inputs = { "The dog is a Malamute.",
                              "The island has beautiful birds.",
                              "The pitch missed home plate.",
                              "Sunday is a weekend day." };
          foreach (string input in inputs)
             Match match = Regex.Match(input, pattern);
             if (match.Success)
                Console.WriteLine("'{0}' precedes 'is'.", match.Value);
                Console.WriteLine("'{0}' does not match the pattern.", input);
    // The example displays the following output:
    //    'dog' precedes 'is'.
    //    'The island has beautiful birds.' does not match the pattern.
    //    'The pitch missed home plate.' does not match the pattern.
    //    'Sunday' precedes 'is'.
    
    Imports System.Text.RegularExpressions
    Module Example
        Public Sub Main()
            Dim pattern As String = "\b\w+(?=\sis\b)"
            Dim inputs() As String = {"The dog is a Malamute.", _
                                       "The island has beautiful birds.", _
                                       "The pitch missed home plate.", _
                                       "Sunday is a weekend day."}
            For Each input As String In inputs
                Dim match As Match = Regex.Match(input, pattern)
                If match.Success Then
                    Console.WriteLine("'{0}' precedes 'is'.", match.Value)
                    Console.WriteLine("'{0}' does not match the pattern.", input)
                End If
        End Sub
    End Module
    ' The example displays the following output:
    '       'dog' precedes 'is'.
    '       'The island has beautiful birds.' does not match the pattern.
    '       'The pitch missed home plate.' does not match the pattern.
    '       'Sunday' precedes 'is'.
    

    正则表达式 \b\w+(?=\sis\b) 可以解释为下表中所示内容。

    subexpression)

    此处,子表达式为任何正则表达式模式。 若要成功匹配,则输入字符串不得匹配 子表达式中的正则表达式模式,尽管匹配的子字符串未包含在匹配结果中。

    零宽度负预测先行断言通常用在正则表达式的开头或结尾。 正则表达式的开头可以定义当其定义了要被匹配的相似但更常规的模式时,不应被匹配的特定模式。 在这种情况下,它通常用于限制回溯。 正则表达式的末尾可以定义不能出现在匹配项末尾处的子表达式。

    下面的示例定义了正则表达式匹配,其在正则表达式的开头使用零宽度预测先行断言,以匹配未以“un”开头的单词。

    using System;
    using System.Text.RegularExpressions;
    public class Example
       public static void Main()
          string pattern = @"\b(?!un)\w+\b";
          string input = "unite one unethical ethics use untie ultimate";
          foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
             Console.WriteLine(match.Value);
    // The example displays the following output:
    //       one
    //       ethics
    //       use
    //       ultimate
    
    Imports System.Text.RegularExpressions
    Module Example
        Public Sub Main()
            Dim pattern As String = "\b(?!un)\w+\b"
            Dim input As String = "unite one unethical ethics use untie ultimate"
            For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
                Console.WriteLine(match.Value)
        End Sub
    End Module
    ' The example displays the following output:
    '       one
    '       ethics
    '       use
    '       ultimate
    

    正则表达式 \b(?!un)\w+\b 可以解释为下表中所示内容。

    下面的示例定义了正则表达式匹配,其在正则表达式的末尾使用零宽度预测先行断言,以匹配未以标点字符结束的单词。

    using System;
    using System.Text.RegularExpressions;
    public class Example
       public static void Main()
          string pattern = @"\b\w+\b(?!\p{P})";
          string input = "Disconnected, disjointed thoughts in a sentence fragment.";
          foreach (Match match in Regex.Matches(input, pattern))
             Console.WriteLine(match.Value);
    // The example displays the following output:
    //       disjointed
    //       thoughts
    //       in
    //       a
    //       sentence
    
    Imports System.Text.RegularExpressions
    Module Example
        Public Sub Main()
            Dim pattern As String = "\b\w+\b(?!\p{P})"
            Dim input As String = "Disconnected, disjointed thoughts in a sentence fragment."
            For Each match As Match In Regex.Matches(input, pattern)
                Console.WriteLine(match.Value)
        End Sub
    End Module
    ' The example displays the following output:
    '       disjointed
    '       thoughts
    '       in
    '       a
    '       sentence
    

    正则表达式 \b\w+\b(?!\p{P}) 可以解释为下表中所示内容。

    subexpression)

    此处,子表达式为任何正则表达式模式。 若要成功匹配,则 子表达式 必须在输入字符串当前位置左侧出现,尽管 subexpression 未包含在匹配结果中。 零宽度正回顾后发断言不会回溯。

    零宽度正预测后发断言通常在正则表达式的开头使用。 它们定义的模式是一个匹配的前提条件,但它不是匹配结果的一部分。

    例如,下面的示例匹配二十一世纪年份的最后两个数字(也就是说,数字“20”要在匹配的字符串之前)。

    using System;
    using System.Text.RegularExpressions;
    public class Example
       public static void Main()
          string input = "2010 1999 1861 2140 2009";
          string pattern = @"(?<=\b20)\d{2}\b";
          foreach (Match match in Regex.Matches(input, pattern))
             Console.WriteLine(match.Value);
    // The example displays the following output:
    //       10
    //       09
    
    Imports System.Text.RegularExpressions
    Module Example
        Public Sub Main()
            Dim input As String = "2010 1999 1861 2140 2009"
            Dim pattern As String = "(?<=\b20)\d{2}\b"
            For Each match As Match In Regex.Matches(input, pattern)
                Console.WriteLine(match.Value)
        End Sub
    End Module
    ' The example displays the following output:
    '       10
    '       09
    

    正则表达式模式 (?<=\b20)\d{2}\b 的含义如下表所示。

    零宽度正回顾后发断言还用于在捕获组中的最后一个或多个字符不得为与该捕获组的正则表达式模式相匹配的字符的子集时限制回溯。 例如,如果组捕获所有的连续单词字符,可以使用零宽度正回顾后发断言要求最后一个字符时按字母顺序的。

    零宽度负回顾后发断言

    以下组构造定义零宽度负回顾后发断言:

    subexpression)

    此处,子表达式为任何正则表达式模式。 若要成功匹配,则 子表达式 不得在输入字符串当前位置的左侧出现。 但是,任何不匹配 subexpression 的子字符串不包含在匹配结果中。

    零宽度负回顾后发断言通常在正则表达式的开头使用。 它们定义的模式预先排除在后面的字符串中的匹配项。 它们还用于在捕获组中的最后一个或多个字符不得为与该捕获组的正则表达式模式相匹配的其中一个或多个字符时限制回溯。 例如,如果如果组捕获了所有的连续单词字符,可以使用零宽度正回顾后发断言要求最后一个字符不是下划线 (_)。

    下面的示例匹配除周末之外的一周的任何一天(也就是星期六和星期日都没有)。

    using System;
    using System.Text.RegularExpressions;
    public class Example
       public static void Main()
          string[] dates = { "Monday February 1, 2010",
                             "Wednesday February 3, 2010",
                             "Saturday February 6, 2010",
                             "Sunday February 7, 2010",
                             "Monday, February 8, 2010" };
          string pattern = @"(?<!(Saturday|Sunday) )\b\w+ \d{1,2}, \d{4}\b";
          foreach (string dateValue in dates)
             Match match = Regex.Match(dateValue, pattern);
             if (match.Success)
                Console.WriteLine(match.Value);
    // The example displays the following output:
    //       February 1, 2010
    //       February 3, 2010
    //       February 8, 2010
    
    Imports System.Text.RegularExpressions
    Module Example
        Public Sub Main()
            Dim dates() As String = {"Monday February 1, 2010", _
                                      "Wednesday February 3, 2010", _
                                      "Saturday February 6, 2010", _
                                      "Sunday February 7, 2010", _
                                      "Monday, February 8, 2010"}
            Dim pattern As String = "(?<!(Saturday|Sunday) )\b\w+ \d{1,2}, \d{4}\b"
            For Each dateValue As String In dates
                Dim match As Match = Regex.Match(dateValue, pattern)
                If match.Success Then
                    Console.WriteLine(match.Value)
                End If
        End Sub
    End Module
    ' The example displays the following output:
    '       February 1, 2010
    '       February 3, 2010
    '       February 8, 2010
    

    正则表达式模式 (?<!(Saturday|Sunday) )\b\w+ \d{1,2}, \d{4}\b 的含义如下表所示。

    subexpression)

    此处,子表达式为任何正则表达式模式。

    通常,如果正则表达式包含一个可选或可替代匹配模式并且备选不成功的话,正则表达式引擎可以在多个方向上分支以将输入的字符串与某种模式进行匹配。 如果未找到使用第一个分支的匹配项,则正则表达式引擎可以备份或回溯到使用第一个匹配项的点并尝试使用第二个分支的匹配项。 此过程可继续进行,直到尝试所有分支。

    仅当嵌套构造不均衡时,才应该定义 (?>子表达式) 语言构造禁用回溯。 正则表达式引擎将在输入字符串中匹配尽可能多的字符。 在没有任何进一步匹配可用时,它将不回溯以尝试备用模式匹配。 (也就是说,该子表达式仅与可由该子表达式单独匹配的字符串匹配;子表达式不会尝试与基于该子表达式的字符串和任何该子表达式之后的子表达式匹配。)

    如果你知道回溯不会成功,则建议使用此选项。 防止正则表达式引擎执行不需要的搜索可以提高性能。

    以下示例展示了原子组如何修改模式匹配的结果。 回溯正则表达式成功匹配一系列重复字符,在字边界上其后为相同字符,但非回溯正则表达式不会匹配。

    using System;
    using System.Text.RegularExpressions;
    public class Example
       public static void Main()
          string[] inputs = { "cccd.", "aaad", "aaaa" };
          string back = @"(\w)\1+.\b";
          string noback = @"(?>(\w)\1+).\b";
          foreach (string input in inputs)
             Match match1 = Regex.Match(input, back);
             Match match2 = Regex.Match(input, noback);
             Console.WriteLine("{0}: ", input);
             Console.Write("   Backtracking : ");
             if (match1.Success)
                Console.WriteLine(match1.Value);
                Console.WriteLine("No match");
             Console.Write("   Nonbacktracking: ");
             if (match2.Success)
                Console.WriteLine(match2.Value);
                Console.WriteLine("No match");
    // The example displays the following output:
    //    cccd.:
    //       Backtracking : cccd
    //       Nonbacktracking: cccd
    //    aaad:
    //       Backtracking : aaad
    //       Nonbacktracking: aaad
    //    aaaa:
    //       Backtracking : aaaa
    //       Nonbacktracking: No match
    
    Imports System.Text.RegularExpressions
    Module Example
        Public Sub Main()
            Dim inputs() As String = {"cccd.", "aaad", "aaaa"}
            Dim back As String = "(\w)\1+.\b"
            Dim noback As String = "(?>(\w)\1+).\b"
            For Each input As String In inputs
                Dim match1 As Match = Regex.Match(input, back)
                Dim match2 As Match = Regex.Match(input, noback)
                Console.WriteLine("{0}: ", input)
                Console.Write("   Backtracking : ")
                If match1.Success Then
                    Console.WriteLine(match1.Value)
                    Console.WriteLine("No match")
                End If
                Console.Write("   Nonbacktracking: ")
                If match2.Success Then
                    Console.WriteLine(match2.Value)
                    Console.WriteLine("No match")
                End If
        End Sub
    End Module
    ' The example displays the following output:
    '    cccd.:
    '       Backtracking : cccd
    '       Nonbacktracking: cccd
    '    aaad:
    '       Backtracking : aaad
    '       Nonbacktracking: aaad
    '    aaaa:
    '       Backtracking : aaaa
    '       Nonbacktracking: No match
    

    非回溯正则表达式 (?>(\w)\1+).\b 的定义如下表所示。

    分组构造和正则表达式对象

    由正则表达式捕获组匹配的子字符串由 System.Text.RegularExpressions.Group 对象表示,其从 System.Text.RegularExpressions.GroupCollection 对象检索,其由 Match.Groups 属性返回。 填充 GroupCollection 对象,如下所示:

  • 集合中的第一个 Group 对象(位于索引零的对象)表示整个匹配。
  • 下一组 Group 对象表示未命名(编号)的捕获组。 它们以在正则表达式中定义的顺序出现,从左至右。 这些组的索引值范围从 1 到集合中未命名捕获组的数目。 (特定组的索引相当于其编号的向后引用。有关向后引用的详细信息,请参阅向后引用构造。)
  • 最后的 Group 对象组表示命名的捕获组。 它们以在正则表达式中定义的顺序出现,从左至右。 第一个名为捕获组的索引值是一个大于最后一个未命名的捕获组的索引。 如果正则表达式中没有未命名捕获组,则第一个命名的捕获组的索引值为 1。
  • 如果将限定符应用于捕获组,则对应的 Group 对象的 Capture.ValueCapture.IndexCapture.Length 属性反映捕获组捕获的最后一个子字符串。 可以检索一整组子字符串,其是按组捕获的并具有来自 CaptureCollection 对象的限定符,其由 Group.Captures 属性返回。

    下面的示例阐释 GroupCapture 对象之间的关系。

    using System;
    using System.Text.RegularExpressions;
    public class Example
       public static void Main()
          string pattern = @"(\b(\w+)\W+)+";
          string input = "This is a short sentence.";
          Match match = Regex.Match(input, pattern);
          Console.WriteLine("Match: '{0}'", match.Value);
          for (int ctr = 1; ctr < match.Groups.Count; ctr++)
             Console.WriteLine("   Group {0}: '{1}'", ctr, match.Groups[ctr].Value);
             int capCtr = 0;
             foreach (Capture capture in match.Groups[ctr].Captures)
                Console.WriteLine("      Capture {0}: '{1}'", capCtr, capture.Value);
                capCtr++;
    // The example displays the following output:
    //       Match: 'This is a short sentence.'
    //          Group 1: 'sentence.'
    //             Capture 0: 'This '
    //             Capture 1: 'is '
    //             Capture 2: 'a '
    //             Capture 3: 'short '
    //             Capture 4: 'sentence.'
    //          Group 2: 'sentence'
    //             Capture 0: 'This'
    //             Capture 1: 'is'
    //             Capture 2: 'a'
    //             Capture 3: 'short'
    //             Capture 4: 'sentence'
    
    Imports System.Text.RegularExpressions
    Module Example
        Public Sub Main()
            Dim pattern As String = "(\b(\w+)\W+)+"
            Dim input As String = "This is a short sentence."
            Dim match As Match = Regex.Match(input, pattern)
            Console.WriteLine("Match: '{0}'", match.Value)
            For ctr As Integer = 1 To match.Groups.Count - 1
                Console.WriteLine("   Group {0}: '{1}'", ctr, match.Groups(ctr).Value)
                Dim capCtr As Integer = 0
                For Each capture As Capture In match.Groups(ctr).Captures
                    Console.WriteLine("      Capture {0}: '{1}'", capCtr, capture.Value)
                    capCtr += 1
        End Sub
    End Module
    ' The example displays the following output:
    '       Match: 'This is a short sentence.'
    '          Group 1: 'sentence.'
    '             Capture 0: 'This '
    '             Capture 1: 'is '
    '             Capture 2: 'a '
    '             Capture 3: 'short '
    '             Capture 4: 'sentence.'
    '          Group 2: 'sentence'
    '             Capture 0: 'This'
    '             Capture 1: 'is'
    '             Capture 2: 'a'
    '             Capture 3: 'short'
    '             Capture 4: 'sentence'
    

    正则表达式模式 (\b(\w+)\W+)+ 从字符串提取各个单词。 其定义如下表所示。

    第二个捕获组匹配句子的每个单词。 第一个捕获组匹配每个单词,连同标点符号和该单词后的空白区域。 Group 对象的索引是 2,提供了有关由第二个捕获组匹配的文本的信息。 可从 CaptureCollection 对象获取捕获组捕获的整组单词,该对象由 Group.Captures 属性返回。

  • 正则表达式语言 - 快速参考
  •