反向引用构造

反向引用提供了标识字符串中的重复字符或子字符串的方便途径。 例如,如果输入字符串包含某任意子字符串的多个匹配项,则可以使用捕获组匹配第一个出现的子字符串,然后使用反向引用匹配后面出现的子字符串。

注意注意

单独语法用于引用替换字符串中命名的和带编号的捕获组。有关更多信息,请参见 替代

.NET Framework 定义引用编号和已命名的捕获组的单独语言元素。 有关捕获组的详细信息,请参阅分组构造

带编号的后向引用

带编号的反向引用使用以下语法:

\数值

其中编号 是正则表达式中捕获组的序号位置。 例如,\4 匹配第四个捕获组的内容。 如果正则表达式模式中未定义编号,则将发生分析错误,并且正则表达式引擎将引发 ArgumentException。 例如,正则表达式 \b(\w+)\s\1 有效,因为 (\w+) 是表达式中的第一个也是唯一一个捕获组。 另一方面,\b(\w+)\s\2 无效,并因为没有捕获组编号 \2 而引发参数异常。

请注意八进制转义代码(如 \16)和使用相同表示法的 \编号 后向引用之间的多义性。 此多义性通过如下方式解决:

  • 表达式 \1 到 \9 总是解释为反向应用,而不是八进制代码。

  • 如果多位表达式的第一个数字是 8 或 9(如 \80 或 \91),则该表达式将被解释为文本。

  • 对于编号为 \10 或更大值的表达式,如果存在与该编号对应的反向引用,则将该表达式视为反向引用;否则,将这些表达式解释为八进制代码。

  • 如果正则表达式包含对未定义的组成员的反向引用,则会发生分析错误,并且正则表达式引擎将引发 ArgumentException

如果有多义性问题,可以使用 \k<名称> 表示法,该表示法是明确的,并且不会与八进制符号代码混淆。 同样,如 \xdd 的十六进制代码是明确的,并且不能与反向引用混淆。

下面的示例查找字符串中双写的单词字符。 它定义了一个正则表达式 (\w)\1,由下列元素组成。

元素

说明

(\w)

匹配字字符,并将其分配给第一捕获组。

\1

匹配下一个值与第一捕获组相同的字符。

Imports System.Text.RegularExpressions

Module Example
   Public Sub Main()
      Dim pattern As String = "(\w)\1"
      Dim input As String = "trellis llama webbing dresser swagger"
      For Each match As Match In Regex.Matches(input, pattern)
         Console.WriteLine("Found '{0}' at position {1}.", _
                           match.Value, match.Index)
      Next   
   End Sub
End Module
' The example displays the following output:
'       Found 'll' at position 3.
'       Found 'll' at position 8.
'       Found 'bb' at position 16.
'       Found 'ss' at position 25.
'       Found 'gg' at position 33.
using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = @"(\w)\1";
      string input = "trellis llama webbing dresser swagger";
      foreach (Match match in Regex.Matches(input, pattern))
         Console.WriteLine("Found '{0}' at position {1}.", 
                           match.Value, match.Index);
   }
}
// The example displays the following output:
//       Found 'll' at position 3.
//       Found 'll' at position 8.
//       Found 'bb' at position 16.
//       Found 'ss' at position 25.
//       Found 'gg' at position 33.

命名的后向引用

命名后向引用通过使用下面的语法进行定义:

\k<name>

或:

\k'name'

其中名称 是在正则表达式模式中定义的捕获组的名称。 如果正则表达式模式中未定义名称,则将发生分析错误,并且正则表达式引擎将引发 ArgumentException

下面的示例查找字符串中双写的单词字符。 它定义了一个正则表达式 (?<char>\w)\k<char>,由下列元素组成。

元素

说明

(?<char>\w)

匹配字字符,并将其分配给名为 char 的捕获组。

\k<char>

匹配下一个值与 char 捕获组相同的字符。

Imports System.Text.RegularExpressions

Module Example
   Public Sub Main()
      Dim pattern As String = "(?<char>\w)\k<char>"
      Dim input As String = "trellis llama webbing dresser swagger"
      For Each match As Match In Regex.Matches(input, pattern)
         Console.WriteLine("Found '{0}' at position {1}.", _
                           match.Value, match.Index)
      Next   
   End Sub
End Module
' The example displays the following output:
'       Found 'll' at position 3.
'       Found 'll' at position 8.
'       Found 'bb' at position 16.
'       Found 'ss' at position 25.
'       Found 'gg' at position 33.
using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = @"(?<char>\w)\k<char>";
      string input = "trellis llama webbing dresser swagger";
      foreach (Match match in Regex.Matches(input, pattern))
         Console.WriteLine("Found '{0}' at position {1}.", 
                           match.Value, match.Index);
   }
}
// The example displays the following output:
//       Found 'll' at position 3.
//       Found 'll' at position 8.
//       Found 'bb' at position 16.
//       Found 'ss' at position 25.
//       Found 'gg' at position 33.

请注意名称 也可以是数字的字符串表示形式。 例如,下面的示例使用正则表达式 (?<2>\w)\k<2> 来查找字符串中双写的单词字符。

Imports System.Text.RegularExpressions

Module Example
   Public Sub Main()
      Dim pattern As String = "(?<2>\w)\k<2>"
      Dim input As String = "trellis llama webbing dresser swagger"
      For Each match As Match In Regex.Matches(input, pattern)
         Console.WriteLine("Found '{0}' at position {1}.", _
                           match.Value, match.Index)
      Next   
   End Sub
End Module
' The example displays the following output:
'       Found 'll' at position 3.
'       Found 'll' at position 8.
'       Found 'bb' at position 16.
'       Found 'ss' at position 25.
'       Found 'gg' at position 33.
using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = @"(?<2>\w)\k<2>";
      string input = "trellis llama webbing dresser swagger";
      foreach (Match match in Regex.Matches(input, pattern))
         Console.WriteLine("Found '{0}' at position {1}.", 
                           match.Value, match.Index);
   }
}
// The example displays the following output:
//       Found 'll' at position 3.
//       Found 'll' at position 8.
//       Found 'bb' at position 16.
//       Found 'ss' at position 25.
//       Found 'gg' at position 33.

反向引用匹配什么

反向引用引用组的最近的定义(当从左到右匹配时,最靠近左侧的定义)。 当组建立多个捕获时,反向引用会引用最近的捕获。

下面的示例包含正则表达式模式 (?<1>a)(?<1>\1b)*,其重新定义命名 \1 的组。 下表描述了正则表达式中的每个模式。

模式

说明

(?<1>a)

匹配字符“a”,并将结果分配给名为 1 的捕获组。

(?<1>\1b)*

将命名为 1 的组的 0 或 1 匹配项与“b”匹配,并将结果分配给名为 1 的捕获的组。

Imports System.Text.RegularExpressions

Module Example
   Public Sub Main()
      Dim pattern As String = "(?<1>a)(?<1>\1b)*"
      Dim input As String = "aababb"
      For Each match As Match In Regex.Matches(input, pattern)
         Console.WriteLine("Match: " + match.Value)
         For Each group As Group In match.Groups
            Console.WriteLIne("   Group: " + group.Value)
         Next
      Next
   End Sub
End Module
' The example display the following output:
'          Group: aababb
'          Group: abb
using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = @"(?<1>a)(?<1>\1b)*";
      string input = "aababb";
      foreach (Match match in Regex.Matches(input, pattern))
      {
         Console.WriteLine("Match: " + match.Value);
         foreach (Group group in match.Groups)
            Console.WriteLine("   Group: " + group.Value);
      }
   }
}
// The example displays the following output:
//          Group: aababb
//          Group: abb

在比较正则表达式与输入字符串(“aababb”)时,正则表达式引擎执行下列操作:

  1. 它从该字符串的开头开始,并成功匹配"a"与表达式 (?<1>a)。 现在 1 组的值为 "a"。

  2. 它前进至第二个字符,并成功匹配字符串 ab 与表达式 \1b 或“ab”。 它将结果“ab”赋给 \1。

  3. 它前进到第四个字符。 表达式 (?<1>\1b) 是要匹配零次或更多次,因此它成功将字符串“abb”与表达式 \1b 匹配。 它将“abb”结果赋回给 \1。

在此示例中,* 是循环限定符 -- 它将重复进行计算,直到正则表达式引擎不能与它所定义的模式匹配时为止。 循环限定符不清除组定义。

如果一个组尚未捕获任何子字符串,则对该组的反向引用是未定义的并且永远不匹配。 这通过正则表达式模式 \b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\b 说明,其定义如下:

模式

说明

\b

从单词边界开始进行匹配。

(\p{Lu}{2})

匹配两个大写字母。 这是第一个捕获组。

(\d{2})?

匹配两个十进制数的零个或一个匹配项。 这是第二个捕获组。

(\p{Lu}{2})

匹配两个大写字母。 这是第三个捕获组。

\b

在单词边界处结束匹配。

输入字符串可以匹配此正则表达式,即使由第二个捕获组定义的两个十进制数字不存在。 下面的示例显示了即使匹配成功,仍会在两个成功的捕获组之间找到空的捕获组。

Imports System.Text.RegularExpressions

Module Example
   Public Sub Main()
      Dim pattern As String = "\b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\b"
      Dim inputs() As String = { "AA22ZZ", "AABB" }
      For Each input As String In inputs
         Dim match As Match = Regex.Match(input, pattern)
         If match.Success Then
            Console.WriteLine("Match in {0}: {1}", input, match.Value)
            If match.Groups.Count > 1 Then
               For ctr As Integer = 1 To match.Groups.Count - 1
                  If match.Groups(ctr).Success Then
                     Console.WriteLine("Group {0}: {1}", _
                                       ctr, match.Groups(ctr).Value)
                  Else
                     Console.WriteLine("Group {0}: <no match>", ctr)
                  End If      
               Next
            End If
         End If
         Console.WriteLine()
      Next      
   End Sub
End Module
' The example displays the following output:
'       Match in AA22ZZ: AA22ZZ
'       Group 1: AA
'       Group 2: 22
'       Group 3: ZZ
'       
'       Match in AABB: AABB
'       Group 1: AA
'       Group 2: <no match>
'       Group 3: BB
using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = @"\b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\b";
      string[] inputs = { "AA22ZZ", "AABB" };
      foreach (string input in inputs)
      {
         Match match = Regex.Match(input, pattern);
         if (match.Success)
         {
            Console.WriteLine("Match in {0}: {1}", input, match.Value);
            if (match.Groups.Count > 1)
            {
               for (int ctr = 1; ctr <= match.Groups.Count - 1; ctr++)
               {
                  if (match.Groups[ctr].Success)
                     Console.WriteLine("Group {0}: {1}", 
                                       ctr, match.Groups[ctr].Value);
                  else
                     Console.WriteLine("Group {0}: <no match>", ctr);
               }
            }
         }
         Console.WriteLine();
      }      
   }
}
// The example displays the following output:
//       Match in AA22ZZ: AA22ZZ
//       Group 1: AA
//       Group 2: 22
//       Group 3: ZZ
//       
//       Match in AABB: AABB
//       Group 1: AA
//       Group 2: <no match>
//       Group 3: BB

请参见

概念

正则表达式语言元素