Construções de referência posterior em expressões regulares

As referências posteriores fornecem uma maneira conveniente de identificar um caractere repetido ou uma subcadeia de caracteres dentro de uma cadeia de caracteres. Por exemplo, se a cadeia de caracteres de entrada contiver várias ocorrências de uma subcadeia de caracteres arbitrária, você poderá corresponder a primeira ocorrência com um grupo de captura e, em seguida, usar uma referência de retorno para corresponder às ocorrências subsequentes da substring.

Nota

Uma sintaxe separada é usada para se referir a grupos de captura nomeados e numerados em cadeias de caracteres de substituição. Para obter mais informações, consulte Substituições.

O .NET define elementos de linguagem separados para se referir a grupos de captura numerados e nomeados. Para obter mais informações sobre como capturar grupos, consulte Agrupando construções.

Referências Traseiras Numeradas

Uma referência de retorno numerada usa a seguinte sintaxe:

\número

onde número é a posição ordinal do grupo de captura na expressão regular. Por exemplo, \4 corresponde ao conteúdo do quarto grupo de captura. Se number não estiver definido no padrão de expressão regular, ocorrerá um erro de análise e o mecanismo de expressão regular lançará um ArgumentExceptionarquivo . Por exemplo, a expressão \b(\w+)\s\1 regular é válida, porque (\w+) é o primeiro e único grupo de captura na expressão. Por outro lado, \b(\w+)\s\2 é inválido e lança uma exceção de argumento, porque não há grupo de captura numerado \2. Além disso, se number identifica um grupo de captura em uma posição ordinal específica, mas esse grupo de captura recebeu um nome numérico diferente de sua posição ordinal, o analisador de expressão regular também lança um ArgumentException.

Observe a ambiguidade entre códigos de escape octais (como \16) e \referências de número que usam a mesma notação. Esta ambiguidade é resolvida do seguinte modo:

  • As expressões \1 através \9 são sempre interpretadas como backreferences, e não como códigos octais.

  • Se o primeiro dígito de uma expressão multidígito for 8 ou 9 (como \80 ou \91), a expressão tal como interpretada como literal.

  • Expressões de \10 e maiores são consideradas backreferences se houver uma backreference correspondente a esse número, caso contrário, elas são interpretadas como códigos octais.

  • Se uma expressão regular contiver uma referência de retorno a um número de grupo indefinido, ocorrerá um erro de análise e o mecanismo de expressão regular lançará um ArgumentExceptionarquivo .

Se a ambiguidade for um problema, você pode usar a notação de nome>, que é inequívoca \k<e não pode ser confundida com códigos de caracteres octais. Da mesma forma, códigos hexadecimais como \xdd são inequívocos e não podem ser confundidos com backreferences.

O exemplo a seguir localiza caracteres de palavra duplicados em uma cadeia de caracteres. Ele define uma expressão regular, (\w)\1, que consiste nos seguintes elementos.

Elemento Description
(\w) Corresponder a um caractere de palavra e atribuí-lo ao primeiro grupo de captura.
\1 Corresponder o próximo caractere que é o mesmo que o valor do primeiro grupo de captura.
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.
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.

Referências traseiras nomeadas

Uma referência de retorno nomeada é definida usando a seguinte sintaxe:

\k<Designação>

ou:

\k'Designação'

onde name é o nome de um grupo de captura definido no padrão de expressão regular. Se name não estiver definido no padrão de expressão regular, ocorrerá um erro de análise e o mecanismo de expressão regular lançará um ArgumentExceptionarquivo .

O exemplo a seguir localiza caracteres de palavra duplicados em uma cadeia de caracteres. Ele define uma expressão regular, (?<char>\w)\k<char>, que consiste nos seguintes elementos.

Elemento Description
(?<char>\w) Corresponder a um caractere de palavra e atribuí-lo a um grupo de captura chamado char.
\k<char> Corresponder o próximo caractere que é o mesmo que o valor do grupo de char captura.
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.
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.

Referências numéricas nomeadas

Em uma backreference nomeada com \k, name também pode ser a representação de cadeia de caracteres de um número. Por exemplo, o exemplo a seguir usa a expressão (?<2>\w)\k<2> regular para localizar caracteres de palavra duplicados em uma cadeia de caracteres. Nesse caso, o exemplo define um grupo de captura que é explicitamente chamado de "2", e a referência de retorno é correspondentemente chamada de "2".

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.
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.

Se name for a representação de cadeia de caracteres de um número, e nenhum grupo de captura tiver esse nome, \k<name> será o mesmo que o número de referência posterior\, onde number é a posição ordinal da captura. No exemplo a seguir, há um único grupo de captura chamado char. A construção backreference refere-se a ela como \k<1>. Como mostra a saída do exemplo, a chamada para o Regex.IsMatch sucesso porque char é o primeiro grupo de captura.

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      Console.WriteLine(Regex.IsMatch("aa", @"(?<char>\w)\k<1>"));
      // Displays "True".
   }
}

Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Console.WriteLine(Regex.IsMatch("aa", "(?<char>\w)\k<1>"))
        ' Displays "True".
    End Sub
End Module

No entanto, se name for a representação de cadeia de caracteres de um número e o grupo de captura nessa posição tiver sido explicitamente atribuído um nome numérico, o analisador de expressão regular não poderá identificar o grupo de captura por sua posição ordinal. Em vez disso, lança um ArgumentException. O único grupo de captura no exemplo a seguir é chamado "2". Como a \k construção é usada para definir uma referência de retorno chamada "1", o analisador de expressão regular não consegue identificar o primeiro grupo de captura e lança uma exceção.

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      Console.WriteLine(Regex.IsMatch("aa", @"(?<2>\w)\k<1>"));
      // Throws an ArgumentException.
   }
}

Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Console.WriteLine(Regex.IsMatch("aa", "(?<2>\w)\k<1>"))
        ' Throws an ArgumentException.
    End Sub
End Module

O que as referências secundárias correspondem

Uma backreference refere-se à definição mais recente de um grupo (a definição mais imediatamente à esquerda, quando corresponde da esquerda para a direita). Quando um grupo faz várias capturas, uma referência posterior refere-se à captura mais recente.

O exemplo a seguir inclui um padrão de expressão regular, (?<1>a)(?<1>\1b)*, que redefine o grupo \1 nomeado. A tabela a seguir descreve cada padrão na expressão regular.

Padrão Description
(?<1>a) Corresponda ao caractere "a" e atribua o resultado ao grupo de captura chamado 1.
(?<1>\1b)* Corresponder zero ou mais ocorrências do grupo nomeado 1 junto com um "b" e atribuir o resultado ao grupo de captura chamado 1.
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
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

Ao comparar a expressão regular com a cadeia de caracteres de entrada ("aababb"), o mecanismo de expressão regular executa as seguintes operações:

  1. Ele começa no início da cadeia de caracteres e combina com êxito "a" com a expressão (?<1>a). O valor do 1 grupo é agora "a".

  2. Ele avança para o segundo caractere e combina com êxito a cadeia de caracteres "ab" com a expressão \1b, ou "ab". Em seguida, atribui o resultado, "ab" a \1.

  3. Avança para o quarto personagem. A expressão (?<1>\1b)* deve ser correspondida zero ou mais vezes, por isso corresponde com êxito a string "abb" com a expressão \1b. Ele atribui o resultado, "abb", de volta a \1.

Neste exemplo, * é um quantificador de looping -- ele é avaliado repetidamente até que o mecanismo de expressão regular não possa corresponder ao padrão que ele define. Os quantificadores de looping não esclarecem as definições de grupo.

Se um grupo não tiver capturado nenhuma substring, uma referência de retorno a esse grupo será indefinida e nunca corresponderá. Isto é ilustrado pelo padrão \b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\bde expressão regular , que é definido da seguinte forma:

Padrão Description
\b Comece a partida em um limite de palavras.
(\p{Lu}{2}) Corresponda a duas letras maiúsculas. Este é o primeiro grupo de captura.
(\d{2})? Corresponder a zero ou uma ocorrência de dois dígitos decimais. Este é o segundo grupo de captura.
(\p{Lu}{2}) Corresponda a duas letras maiúsculas. Este é o terceiro grupo de captura.
\b Termine a partida com um limite de palavras.

Uma cadeia de caracteres de entrada pode corresponder a essa expressão regular mesmo que os dois dígitos decimais definidos pelo segundo grupo de captura não estejam presentes. O exemplo a seguir mostra que, embora a correspondência seja bem-sucedida, um grupo de captura vazio é encontrado entre dois grupos de captura bem-sucedidos.

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
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

Consulte também