Construcciones de referencia inversa en expresiones regularesBackreference Constructs in Regular Expressions

Las referencias inversas proporcionan una forma cómoda de identificar un carácter o subcadena repetidos dentro de una cadena.Backreferences provide a convenient way to identify a repeated character or substring within a string. Por ejemplo, si la cadena de entrada contiene varias apariciones de una subcadena arbitraria, puede buscar una coincidencia con la primera aparición con un grupo de captura y después usar una referencia inversa para buscar una coincidencia con las siguientes apariciones de la subcadena.For example, if the input string contains multiple occurrences of an arbitrary substring, you can match the first occurrence with a capturing group, and then use a backreference to match subsequent occurrences of the substring.

Nota

Se usa una sintaxis independiente para hacer referencia a los grupos de captura con numeración y con nombre de las cadenas de reemplazo.A separate syntax is used to refer to named and numbered capturing groups in replacement strings. Para obtener más información, consulte Substituciones.For more information, see Substitutions.

.NET define elementos del lenguaje independientes para hacer referencia a los grupos de captura con numeración y con nombre..NET defines separate language elements to refer to numbered and named capturing groups. Para más información sobre los grupos de captura con nombre, vea Construcciones de agrupamiento.For more information about capturing groups, see Grouping Constructs.

Referencias inversas con numeraciónNumbered Backreferences

Una referencia inversa con numeración usa la siguiente sintaxis:A numbered backreference uses the following syntax:

\ número\ number

donde número es la posición ordinal del grupo de captura en la expresión regular.where number is the ordinal position of the capturing group in the regular expression. Por ejemplo, \4 coincide con el contenido del cuarto grupo de captura.For example, \4 matches the contents of the fourth capturing group. Si número no está definido en el patrón de expresión regular, se produce un error de análisis y el motor de expresiones regulares produce una clase ArgumentException.If number is not defined in the regular expression pattern, a parsing error occurs, and the regular expression engine throws an ArgumentException. Por ejemplo, la expresión regular \b(\w+)\s\1 es válida, porque (\w+) es el primer y único grupo de captura de la expresión.For example, the regular expression \b(\w+)\s\1 is valid, because (\w+) is the first and only capturing group in the expression. Por otro lado, \b(\w+)\s\2 no es válida y produce una excepción de argumento porque no hay ningún grupo de captura con numeración \2.On the other hand, \b(\w+)\s\2 is invalid and throws an argument exception, because there is no capturing group numbered \2. Además, si número identifica un grupo de captura en una posición ordinal determinada, pero a ese grupo de captura se le ha asignado un nombre numérico que no sea su posición ordinal, el analizador de expresiones regulares también produce una excepción ArgumentException.In addition, if number identifies a capturing group in a particular ordinal position, but that capturing group has been assigned a numeric name different than its ordinal position, the regular expression parser also throws an ArgumentException.

Tenga en cuenta la ambigüedad entre los códigos de escape octales (como \16) y las referencias inversas \número que usan la misma notación.Note the ambiguity between octal escape codes (such as \16) and \number backreferences that use the same notation. Esta ambigüedad se resuelve de la siguiente forma:This ambiguity is resolved as follows:

  • Las expresiones \1 a \9 siempre se interpretan como referencias inversas y no como códigos octales.The expressions \1 through \9 are always interpreted as backreferences, and not as octal codes.

  • Si el primer dígito de una expresión con varios dígitos es 8 o 9 (como \80 o \91), la expresión se interpreta como un literal.If the first digit of a multidigit expression is 8 or 9 (such as \80 or \91), the expression as interpreted as a literal.

  • Las expresiones a partir de \10 y superiores se consideran referencias inversas si hay una referencia inversa que se corresponda con ese número; en caso contrario, se interpretan como códigos octales.Expressions from \10 and greater are considered backreferences if there is a backreference corresponding to that number; otherwise, they are interpreted as octal codes.

  • Si una expresión regular contiene una referencia inversa a un número de grupo sin definir, se produce un error de análisis y el motor de expresiones regulares produce una clase ArgumentException.If a regular expression contains a backreference to an undefined group number, a parsing error occurs, and the regular expression engine throws an ArgumentException.

Si la ambigüedad constituye un problema, puede usar la notación \k<nombre>, que es inequívoca y no se puede confundir con códigos de caracteres octales.If the ambiguity is a problem, you can use the \k<name> notation, which is unambiguous and cannot be confused with octal character codes. De forma similar, los códigos hexadecimales como \xdd son inequívocos y no se pueden confundir con las referencias inversas.Similarly, hexadecimal codes such as \xdd are unambiguous and cannot be confused with backreferences.

En el ejemplo siguiente, se buscan caracteres de palabra duplicados en una cadena.The following example finds doubled word characters in a string. Define una expresión regular, (\w)\1, que consta de los siguientes elementos.It defines a regular expression, (\w)\1, which consists of the following elements.

ElementoElement DescriptionDescription
(\w) Coincide con un carácter que se usa para formar palabras y se lo asigna al primer grupo de captura.Match a word character and assign it to the first capturing group.
\1 Coincide con el siguiente carácter que sea igual que el valor del primer grupo de captura.Match the next character that is the same as the value of the first capturing group.
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.

Referencias inversas con nombreNamed Backreferences

Una referencia inversa con nombre se define mediante la sintaxis siguiente:A named backreference is defined by using the following syntax:

\k< nombre >\k< name >

O bienor:

\k' nombre '\k' name '

donde nombre es el nombre de un grupo de captura definido en el patrón de expresión regular.where name is the name of a capturing group defined in the regular expression pattern. Si nombre no está definido en el patrón de expresión regular, se produce un error de análisis y el motor de expresiones regulares produce una clase ArgumentException.If name is not defined in the regular expression pattern, a parsing error occurs, and the regular expression engine throws an ArgumentException.

En el ejemplo siguiente, se buscan caracteres de palabra duplicados en una cadena.The following example finds doubled word characters in a string. Define una expresión regular, (?<char>\w)\k<char>, que consta de los siguientes elementos.It defines a regular expression, (?<char>\w)\k<char>, which consists of the following elements.

ElementoElement DescriptionDescription
(?<char>\w) Coincide con un carácter que se usa para formar palabras y se lo asigna a un grupo de captura denominado char.Match a word character and assign it to a capturing group named char.
\k<char> Coincide con el siguiente carácter que sea igual que el valor del grupo de captura char.Match the next character that is the same as the value of the char capturing group.
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.

Referencias inversas numéricas con nombreNamed numeric backreferences

En una referencia inversa con \k, nombre también puede ser la representación de cadena de un número.In a named backreference with \k, name can also be the string representation of a number. Por ejemplo, en el ejemplo siguiente, se usa la expresión regular (?<2>\w)\k<2> para buscar caracteres de palabra duplicados en una cadena.For example, the following example uses the regular expression (?<2>\w)\k<2> to find doubled word characters in a string. En este caso, el ejemplo define un grupo de captura que se denomina explícitamente "2" y la referencia inversa se denomina también "2".In this case, the example defines a capturing group that is explicitly named "2", and the backreference is correspondingly named "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.

Si nombre es la representación de cadena de un número y ningún grupo de captura tiene ese nombre, \k<nombre> es igual que la referencia inversa \número, donde número es la posición ordinal de la captura.If name is the string representation of a number, and no capturing group has that name, \k<name> is the same as the backreference \number, where number is the ordinal position of the capture. En el ejemplo siguiente, hay un único grupo de captura denominado char.In the following example, there is a single capturing group named char. La construcción de referencia inversa hace referencia a él como \k<1>.The backreference construct refers to it as \k<1>. Como muestra la salida del ejemplo, la llamada a Regex.IsMatch se realiza correctamente porque char es el primer grupo de captura.As the output from the example shows, the call to the Regex.IsMatch succeeds because char is the first capturing group.

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

En cambio, si nombre es la representación de cadena de un número y al grupo de captura de esa posición se le ha asignado explícitamente un nombre numérico, el analizador de expresiones regulares no puede identificar el grupo de captura por su posición ordinal.However, if name is the string representation of a number and the capturing group in that position has been explicitly assigned a numeric name, the regular expression parser cannot identify the capturing group by its ordinal position. En su lugar, produce una excepción ArgumentException.Instead, it throws an ArgumentException. El único grupo de captura del siguiente ejemplo se denomina "2".The only capturing group in the following example is named "2". Dado que la construcción \k se usa para definir una referencia inversa denominada "1", el analizador de expresiones regulares no puede identificar el primer grupo de captura y produce una excepción.Because the \k construct is used to define a backreference named "1", the regular expression parser is unable to identify the first capturing group and throws an exception.

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

Con qué coinciden las referencias inversasWhat Backreferences Match

Una referencia inversa constituye la definición más reciente de un grupo (la definición más inmediatamente a la izquierda, al coincidir de izquierda a derecha).A backreference refers to the most recent definition of a group (the definition most immediately to the left, when matching left to right). Cuando un grupo realiza varias capturas, una referencia inversa se refiere a la captura más reciente.When a group makes multiple captures, a backreference refers to the most recent capture.

En el ejemplo siguiente, se incluye un patrón de expresión regular, (?<1>a)(?<1>\1b)*, que redefine el grupo con nombre \1.The following example includes a regular expression pattern, (?<1>a)(?<1>\1b)*, which redefines the \1 named group. En la tabla siguiente, se describe cada patrón de la expresión regular.The following table describes each pattern in the regular expression.

ModeloPattern DescriptionDescription
(?<1>a) Coincide con el carácter "a" y asigna el resultado al grupo de captura denominado 1.Match the character "a" and assign the result to the capturing group named 1.
(?<1>\1b)* Coincide con ninguna o más apariciones del grupo denominado 1 junto con una "b" y asigna el resultado al grupo de captura denominado 1.Match zero or more occurrences of the group named 1 along with a "b", and assign the result to the capturing group named 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

Al comparar la expresión regular con la cadena de entrada ("aababb"), el motor de expresiones regulares realiza las siguientes operaciones:In comparing the regular expression with the input string ("aababb"), the regular expression engine performs the following operations:

  1. Comienza al principio de la cadena y hace que "a" coincida correctamente con la expresión (?<1>a).It starts at the beginning of the string, and successfully matches "a" with the expression (?<1>a). Ahora, el valor del grupo 1 es "a".The value of the 1 group is now "a".

  2. Se desplaza hasta el segundo carácter y hace que la cadena "ab" coincida correctamente con la expresión \1b, o "ab".It advances to the second character, and successfully matches the string "ab" with the expression \1b, or "ab". Después, asigna el resultado "ab" a \1.It then assigns the result, "ab" to \1.

  3. Se desplaza hasta el cuarto carácter.It advances to the fourth character. La expresión (?<1>\1b)* puede coincidir cero o más veces, así que la cadena "abb" coincide correctamente con la expresión \1b.The expression (?<1>\1b)* is to be matched zero or more times, so it successfully matches the string "abb" with the expression \1b. Vuelve a asignar el resultado, "abb", a \1.It assigns the result, "abb", back to \1.

En este ejemplo, * es un cuantificador de bucle: se evalúa repetidas veces hasta que el motor de expresiones regulares no puede coincidir con el patrón que define.In this example, * is a looping quantifier -- it is evaluated repeatedly until the regular expression engine cannot match the pattern it defines. Los cuantificadores de bucle no borran las definiciones de grupo.Looping quantifiers do not clear group definitions.

Si un grupo no ha capturado ninguna subcadena, no se define una referencia inversa a ese grupo y no coincide nunca.If a group has not captured any substrings, a backreference to that group is undefined and never matches. Así lo ilustra el patrón de expresión regular \b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\b que se define de la siguiente forma:This is illustrated by the regular expression pattern \b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\b, which is defined as follows:

ModeloPattern DescriptionDescription
\b Comienza la búsqueda de coincidencias en un límite de palabras.Begin the match on a word boundary.
(\p{Lu}{2}) Coincide con dos letras mayúsculas.Match two uppercase letters. Este es el primer grupo de captura.This is the first capturing group.
(\d{2})? Coincide con una o ninguna aparición de dos dígitos decimales.Match zero or one occurrence of two decimal digits. Este es el segundo grupo de captura.This is the second capturing group.
(\p{Lu}{2}) Coincide con dos letras mayúsculas.Match two uppercase letters. Éste es el tercer grupo de captura.This is the third capturing group.
\b Finalizar la búsqueda de coincidencias en un límite de palabras.End the match on a word boundary.

Una cadena de entrada puede coincidir con esta expresión regular aunque no estén presentes los dos dígitos decimales que define el segundo grupo de captura.An input string can match this regular expression even if the two decimal digits that are defined by the second capturing group are not present. En el ejemplo siguiente, se muestra que, aunque la coincidencia es correcta, hay un grupo de captura vacío entre dos grupos de captura correctos.The following example shows that even though the match is successful, an empty capturing group is found between two successful capturing groups.

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

Vea tambiénSee also