Compartir a través de


Construcciones de referencia inversa

Las referencias inversas proporcionan una manera conveniente de identificar un carácter o subcadena repetido dentro de una cadena. Por ejemplo, si la cadena de entrada contiene varias veces la misma subcadena arbitraria, puede asociar la primera aparición con un grupo de captura y, a continuación, utilizar una referencia inversa para hacerla coincidir con las siguientes apariciones de la subcadena.

NotaNota

Una sintaxis independiente se utiliza para hacer referencia a grupos de captura con nombre y número en cadenas de reemplazo.Para obtener más información, vea Sustituciones.

.NET Framework define distintos elementos del lenguaje para hacer referencia a grupos de captura numerados y con nombre. Para obtener más información sobre los grupos de capturas, vea Construcciones de agrupamiento.

Referencias inversas numeradas

Una referencia inversa numerada usa la siguiente sintaxis:

\number

donde número es la posición ordinal del grupo de captura en la expresión regular. Por ejemplo, \4 coincide con el contenido del cuarto grupo de capturas. Si número no se define en el modelo de expresión regular, se producirá un error de análisis y el motor de expresiones regulares iniciará una excepción ArgumentException. Por ejemplo, la expresión regular \b(\w+)\s\1 es válida porque (\w+) es el primer y único grupo de capturas de la expresión. Por otro lado, \b(\w+)\s\2 no es válido e inicia una excepción de argumento porque no hay ningún grupo de capturas con el número \2.

Observe la ambigüedad existente entre los códigos de escape octales (como \16) y las referencias inversas \número que utilizan la misma notación. Esta ambigüedad se resuelve como sigue:

  • Las expresiones \1 a \9 siempre se interpretan como referencias inversas, no como códigos octales.

  • Si el primer dígito de una expresión con varios dígitos es 8 ó 9 (como \80 o \91), se interpretará la expresión como un literal.

  • Las expresiones de \10 y mayores están consideradas referencias inversas si hay una referencia inversa que corresponde a ese número; de lo contrario, se interpretan como códigos octales.

  • Si una expresión regular contiene una referencia inversa a un número de grupo indefinido, se produce un error de análisis y el motor de expresiones regulares inicia una excepción ArgumentException.

Si la ambigüedad constituye un problema, puede utilizar la notación \k<nombre>, que no produce ambigüedades ni puede confundirse con códigos de caracteres octales. De forma similar, los códigos hexadecimales como \xdd son inequívocos y no se pueden confundir con referencias inversas.

El ejemplo siguiente busca caracteres de palabra duplicados en una cadena. Define una expresión regular, (\w)\1, que se compone de los siguientes elementos.

Elemento

Descripción

(\w)

Busca una coincidencia con un carácter de palabra y la asigna al primero grupo de capturas.

\1

Busca una coincidencia con el siguiente carácter que sea igual que el valor del primer grupo de capturas.

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.

Referencias inversas con nombre

Una referencia inversa con nombre se define con la sintaxis siguiente:

\k<name>

O bien

\k'name'

donde nombre es el nombre de un grupo de captura definido en el modelo de expresión regular. Si nombre no se define en el modelo de expresión regular, se producirá un error de análisis y el motor de expresiones regulares iniciará una excepción ArgumentException.

El ejemplo siguiente busca caracteres de palabra duplicados en una cadena. Define una expresión regular, (?<char>\w)\k<char>, que se compone de los siguientes elementos.

Elemento

Descripción

(?<char>\w)

Busca una coincidencia con un carácter de palabra y la asigna a un grupo de capturas denominado char.

\k<char>

Busca una coincidencia con el siguiente carácter que sea igual que el valor del grupo de capturas 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.

Observe que nombre también puede ser la representación de cadena de un número. En el siguiente ejemplo, se utiliza la expresión regular (?<2>\w)\k<2> para buscar caracteres de palabra duplicados en una cadena.

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.

Qué coincidencias buscan las referencias inversas

Una referencia inversa constituye la definición más reciente de un grupo (la definición que se encuentra más a la izquierda, cuando la búsqueda de coincidencias es de izquierda a derecha). Cuando un grupo realiza varias capturas, una referencia inversa se corresponde con la captura más reciente.

En el siguiente ejemplo se incluye un modelo de expresión regular, (?<1>a)(?<1>\1b)*, que vuelve a definir el grupo con nombre \1. La tabla siguiente describe cada modelo de la expresión regular.

Modelo

Descripción

(?<1>a)

Busca una coincidencia con el carácter "a" y asigna el resultado al grupo de capturas denominado 1.

(?<1>\1b)*

Busca 0 ó 1 coincidencia con el grupo denominado 1 junto con una "b" y asigna el resultado al grupo de capturas denominado 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

Al comparar la expresión regular con la cadena de entrada ("aababb"), el motor de expresiones regulares realiza las siguientes operaciones:

  1. Comienza al principio de la cadena y hace coincidir "a" con la expresión (?<1>a). El valor del grupo 1 es ahora "a".

  2. Avanza hasta el segundo carácter y hace coincidir correctamente la cadena "ab" con la expresión \1b o "ab". A continuación, asigna el resultado, "ab", a \1.

  3. Avanza hasta el cuarto carácter. La expresión (?<1>\1b) va a coincidir cero o más veces, de modo que coincida correctamente la cadena "abb" con la expresión \1b. Vuelve a asignar el resultado, "abb", a \1.

En este ejemplo, * es un cuantificador de bucle: se evalúa repetidas veces hasta que el motor de expresiones regulares no encuentre coincidencias con el modelo definido. Los cuantificadores de bucle no borran las definiciones de grupo.

Si un grupo no captura ninguna subcadena, la referencia inversa a ese grupo no está definida y nunca coincide con ninguna cadena. Esto se ilustra mediante el modelo de expresión regular \b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\b, que se define como sigue:

Modelo

Descripción

\b

Iniciar la búsqueda de coincidencias en un límite de palabras.

(\p{Lu}{2})

Busca una coincidencia con dos letras mayúsculas. Éste es el primer grupo de captura.

(\d{2})?

Busca cero o una coincidencia con dos dígitos decimales. Éste es el segundo grupo de captura.

(\p{Lu}{2})

Busca una coincidencia con dos letras mayúsculas. Éste es el tercer grupo de captura.

\b

Finalizar la búsqueda de coincidencias en un límite de palabras.

Una cadena de entrada puede coincidir con esta expresión regular aun cuando los dos dígitos decimales que son definidos por el segundo grupo capturador no están presentes. El ejemplo siguiente muestra que aunque la coincidencia es correcta, hay un grupo capturador vacío entre dos grupos capturadores correctos.

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

Vea también

Conceptos

Elementos del lenguaje de expresiones regulares