TOC

This article is currently in the process of being translated into Spanish (~99% done).

Regular Expressions (Regex):

Searching with the Regex Class

Como discutimos en el artículo previo, las Expresiones Regulares le permiten definir patrones de búsqueda para trabajar con cadenas. Para procesar este patrón de búsqueda, el ambiente .NET viene con una clase muy versatil: La clase Regex. En este artículo, definiremos algunos patrones de búsqueda y los usaremos con la clase Regex, pero por favor tenga en cuenta que la sintaxis de las Expresiones Regulares puede ser más complicada y que esto es un tutorial de C# y no tutorial de Regex. En vez de eso, usare algunos patrones simples Regex para demostrar como usted puede trabajar con ellas en C#. Si quiere conocer más acerca de Expresiones Regulares, le puedo recomendar este Tutorial de Expresión Regular.

El Método IsMatch()

En este primer ejemplo, usare uno de los métodos más básicos de la clase Regex llamado IsMatch. Simplemente retorna verdadero o falso, dependiendo si hay una o varias coincidencias encontradas en la cadena probada:

string testString = "John Doe, 42 years";
Regex regex = new Regex("[0-9]+");
if (regex.IsMatch(testString))
    Console.WriteLine("String contains numbers!");
else
    Console.WriteLine("String does NOT contain numbers!");

Definimos una cadena de prueba y entonces creamos una instancia de la clase Regex. Pasamos la Expresión Regular actual como una cadena - en este caso, la regex especifica que que estamos buscando un número de cualquier longitud. Entonces escribimos una línea de texto dependiendo de si la cadena de prueba tiene una concidencia con el patrón de búsqueda representado por la regex.

La Clase Match y el Método Match

En este siguiente ejemplo, capturaremos el número encontrado en la cadena de prueba y lo presentaremos al usuario, en vez de sólo verificar que está allí:

string testString = "John Doe, 42 years";
Regex regex = new Regex("[0-9]+");
Match match = regex.Match(testString);
if (match.Success)
    Console.WriteLine("Number found: " + match.Value);

Usamos la misma regex y la cadena de prueba como antes. Invoco al método Match(), el cual retornará una instancia de la clase Match - esto sucederá se encuentre o no una coincidencia en realidad. Para asegurar que la coincidencia ha sido encontrada, checo la propiedad Success. Una vez que estoy seguro que la coincidencia ha sido encontrada, uso la propiedad Value para recuperarla.

La clase Match contiene más información útil que sólo la cadena coincidente - por ejemplo, puede fácilmente encontrar donde fue encontrada, que tan larga es y más.

string testString = "John Doe, 42 years";
Regex regex = new Regex("[0-9]+");
Match match = regex.Match(testString);
if (match.Success)
    Console.WriteLine("Match found at index " + match.Index + ". Length: " + match.Length);

Las propiedades Index y Length son usadas aquí para mostrar información acerca de la ubicación y longitud de la cadena coincidente.

Grupos de Captura

En el primer par de ejemplos, hemos encontrado sólo un valor en nuestra cadena de búsqueda, ¡pero las Expresiones Regulares pueden, por supuesto, hacer mucho más que esto! Por ejemplo, podemos encontrar ambos el nombre y la edad en nuestra cadena de prueba, mientras ignoremos la información irrelevante como la coma y el texto "years". Hacer estas cosas es muy sencillo para Expresiones Regulares, pero si no está familiarizado con la sintaxis, puede parecer muy complicado, pero intentémoslo de cualquier forma:

string testString = "John Doe, 42 years";
Regex regex = new Regex(@"^([^,]+),\s([0-9]+)");
Match match = regex.Match(testString);
if (match.Success)
    Console.WriteLine("Name: " + match.Groups[1].Value + ". Age: " + match.Groups[2].Value);

He modificado la regex para que busque cualquier cosa que NO sea una coma - este valor es puesto en el primer grupo de captura, gracias a los paréntesis rodeando. Luego busca la coma de separación y después de ésta, un número, el cual es puesto en el segundo grupo de captura (de nuevo, gracias a los paréntesis rodeando). En la última línea, uso la propiedad Groups para accesar a los grupos coincidentes. Uso el índice 1 para el nombre y el índice 2 para la edad ya que siguen el orden en el cual los grupos coincidentes fueron definidos en la cadena regex (el índice 0 contiene la coincidencia entera).

Grupos de Captura Nombrados

Tan pronto como el regex se haga más avanzado/largo que el usado aquí, los grupos de captura numerados podrían convertirse en inmanejables por que usted tiene que recordar constantemente el orden y los índices de ellos. Afortunadamente para nosotros, las Expresiones Regulares y el ambiente .NET soportan grupos de captura nombrados, los cuales le permitirán dar a cada grupo un nombre en el regex y entonces hacer la referencia en la propiedad Gruops. Revise esto en el ejemplo reescrito, donde usamos grupos nombrados en vez de numerados:

string testString = "John Doe, 42 years";
Regex regex = new Regex(@"^(?<name>[^,]+),\s(?<age>[0-9]+)");
Match match = regex.Match(testString);
if (match.Success)
    Console.WriteLine("Name: " + match.Groups["name"].Value + ". Age: " + match.Groups["age"].Value);

Trabajo exactamente igual que antes, pero ahora puede usar los nombres lógicos para buscar los valores coincidentes en vez de tener que recordar el índice correcto. Esto pudiera no ser una gran diferencia en nuestro ejemplo simple, pero como mencioné usted lo apreciará definitivamente cuando sus Expresiones Regulares crezcan en complejidad y longitud.

La Clase MatchCollection

La clase Match es un camino que andar si sólo quiere trabajar con una sóla coincidencia (recuerde que una coincidencia puede contener múltiples valores, como vimos en los ejemplos previos), pero a veces quiere trabajar con varias coincidencias a la vez. Para esto, tenemos el método Matches() el cual regresará un objeto de la clase MatchCollection. Contendrá todos los valores coincidentes, en el orden en el cual fueron encontrados. Veamos como puede ser usada:

string testString = "123-456-789-0";
Regex regex = new Regex(@"([0-9]+)");
MatchCollection matchCollection = regex.Matches(testString);
foreach (Match match in matchCollection)
    Console.WriteLine("Number found at index " + match.Index + ": " + match.Value);

He cambiado la regex y la cadena de prueba, comparado al ejemplo previo. Ahora tenemos una cadena de prueba la cual contiene varios números y una regex la cual busca específicamente cadenas consistiendo de uno o más números. Usamos el método Matches() para obtener una MatchCollection de nuestra regex, la cual contiene las coincidencias encontradas en la cadena. En este caso, hay cuatro coincidencias, las cuales escribimos una tras otra con un ciclo foreach. El resultado se verá algo como esto:

Number found at index 0: 123
Number found at index 4: 456
Number found at index 8: 789
Number found at index 12: 0

Si no fueren encontradas coincidencias, una MatchCollection vacía habría sido retornada.

Resumen

Con ayuda de la clase Regex, junto con las clases Match y MatchCollection, podemos fácilmente hacer búsqueda de cadenas muy avanzada. La sintáxis de las Expresiones Regualres parece ser compleja, pero una vez que la aprende, tendrá una herramienta muy poderosa. Aún si no lo quiere invertir el tiempo para aprencer la sintáxis regex, puede a menudo encontrar expresiones para necesidades específicas, creadas por otros programadores, con una simple búsqueda en Google. Tan pronto como haya escrito o tomado prestada una cadena regex, puede usarla para sus propósitos con las técnicas y las clases demostradas en este artículo.

Pero la búsqueda es solamente una parte de la diversión - también puede hacer algunas operaciones geniales de búsqueda/reemplazo con Expresiones Regulares. Revisaremos esto en uno de los siguientes artículos.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!