GuilleSQL :: Microsoft SQL Server, SSIS, y más !!

Regular Expressions


Las Regular Expressions (Expresiones Regulares), cuyo diminutivo conocido suele ser Regex, son una simple cadena de texto que permite actuar como un patrón de búsqueda. Su utilidad es muy amplia, en primer lugar, por su gran potencia para poder describir patrones de búsqueda muy complejos, y en segundo lugar, por su amplia implementación tanto en diferentes entornos de desarrollo (.Net, Java, PHP, Perl, etc.) como en diferentes herramientas como puedan ser editores de texto avanzados.

Este artículo intenta ser una guía rápida y básica sobre las Expresiones Regulares (Regular Expressions o Regex). La sintaxis disponible para la creación de Regex es bastante completa, pudiendo construirse expresiones realmente complicadas. Hay que tener cuidado, porque en ocasiones, el orden de los factores si altera el resultado, como iremos viendo a lo largo del presente artículo (ej: las Disyunciones, Clases de Caracteres, Valores Opcionales, etc.). Además, habitualmente podremos construir diferentes Regular Expressions que produzcan el mismo resultado, pero debe tenerse en cuenta que pueden tener una diferencia importante en el consumo de recursos del sistema.

Carácter de escape, Metacaracteres y Literales

Una de las primeras cosas que deberemos conocer, es que el carácter de escape es la barra invertida \. Además, existen once caracteres especiales, denominados Metacaracteres, que se exponen a continuación separados por comas: [, \, ^, $, ., |, ?, *, +, (, ). De este modo, es posible realizar una búsqueda literal de una cadena especificando como Expresión Regular la propia cadena, pero teniendo en cuenta, que si la cadena que se desea buscar contiene algún Metacaracter, deberemos prefijarlo con el carácter de escape, por supuesto, también teniendo en cuenta que las Expresiones Regulares son susceptibles de mayúsculas y minúsculas.

Deberemos tener cuidado al utilizar el carácter de escape seguido de un carácter que no sea un Metacaracter, ya que en algunos casos tomará un significado especial (ej: \d simboliza un dígito, esto es, número; otros casos simbolizan caracteres no visibles), mientras que en otros provocará un error. Ejemplos:

  • \d – Un dígito cualquiera
  • \D – Cualquier carácter excepto un dígito. Es equivalente a [^\d] (ver más adelante el apartado de Clases de Caracteres).
  • \w – Un Word Character. Su valor puede depender de la implementación. Suele ser equivalente a [a-zA-Z0-9_] (ver más adelante el apartado de Clases de Caracteres).
  • \W – Cualquier carácter excepto un Word Character. Es equivalente a [^\w] (ver más adelante el apartado de Clases de Caracteres).
  • \s – Un espacio, tabulador o salto de línea.
  • \S – Cualquier carácter excepto espacio, tabulador o salto de línea. Es equivalente a [^\s].
  • \t – Un tabulador
  • \r – Un retorno de carro
  • \n – Una nueva línea
  • \a – Un pitido
  • \e – Escape
  • \xA3 – El valor hexadecimal A3

A continuación se incluyen varios ejemplos, como resumen de lo comentado:

Cadena origen Regex Resultado
Esta es mi casa de vacaciones ca Encuentra la primera ocurrencia del texto "ca"
Esta es mi casa de vacaciones Ca No encuentra ninguna ocurrencia
2+2=4 \+2 Encuentra la primera ocurrencia del texto "+2"
c:\config.20101214.sys c:\\ Encuentra la primera ocurrencia del texto "c:\"
c:\config.20101214.sys \d Encuentra la primera ocurrencia de un dígito.
c:\config.20101214.sys \g Error, \g no tiene ningún significado.
Portal GuilleSQL © 2007-2010 \xA9 Encuentra la primera ocurrencia del símbolo ©, cuyo valor hexadecimal es A9.

Clases de Caracteres

Es posible buscar por un carácter particular dentro de un conjunto discreto. Es decir, si tenemos una cadena, buscar la primera ocurrencia de un determinado valor dentro de un conjunto de posibles valores. Para ello deberemos utilizar corchetes en nuestra expresión regular, indicando dentro de los corchetes, el conjunto válido de caracteres que estamos buscando.

Es determinante el orden de los posibles valores especificados en la Clase de Caracteres, de tal modo, que primero se comprobará la coincidencia para el primer valor, seguidamente para el segundo, y así sucesivamente.

Además, es posible especificar un rango de caracteres utilizando un guión, por ejemplo, todos las letras minúsculas entre la "a" y la "j". Incluso es posible combinar varios rangos y valores discretos en la misma expresión regular.

Otro detalle importante, es que se puede buscar por todos los valores excepto por los indicados en la Clase de Caracteres, para lo que nos apoyaremos en el Metacaracter ^, para negar la Clase de Caracteres.

Debe tenerse en cuenta que dentro de la definición de una Clase de Caracteres, esto es, dentro de los corchetes, los únicos caracteres que se tratarán como caracteres especiales (requiriendo prefijarlos por el carácter de escape \) son: ], \, ^, y -.

Cadena origen Regex Resultado
Estoy buscando a Pepe Pep[ea] Encuentra la primera ocurrencia del texto "Pepe" ó "Pepa", y en este orden.
Me han promocionado a Level C. Level [A-H] Encuentra la primera ocurrencia del texto "Level A" ó "Level B" o … o "Level H".
Me han promocionado a Level 2. Level [A-H0-7] Encuentra la primera ocurrencia del texto "Level A" ó "Level B" ó … ó "Level H" ó "Level 0" ó … ó "Level 7". Utiliza dos rangos: A-H y 0-7.
Prueba simple de texto libre en español [^a-zA-Z0-9 ñÑ] Comprueba que sólo se utilicen letras o números. Para ello, se utiliza la negación con ^, varios rangos (a-z, A-Z, y 0-9) y varios valores discretos (ñ, Ñ, y un espacio en blanco).
Prueba simple de texto libre [^\da-fA-F] Comprueba que sólo se utilicen valores alfanuméricos. Es equivalente a [0-9a-fA-F].
2 + 2 = 4 [+\-*/] Encuentra la primera ocurrencia de cualquiera de los operadores +, -, * ó /. Utiliza el carácter de escape sólo para el signo –. El resto no requiere carácter de escape, al estar dentro de una Clase de Caracteres.

El carácter comodín

El Metacaracter del punto (.) se utiliza como un comodín, representando cualquier valor excepto el de nueva línea. Resulta equivalente a [^\n] ó [^\r\n], en función de que se trate de Windows o Unix.

En algunos entornos es posible configurarlos para que el carácter comodín incluya también el valor de nueva línea. A continuación se muestra un ejemplo aplicable a .Net Framework: Regex.Match("Cadena origen de búsqueda", "Expresión Regular", RegexOptions.Singleline).

Cadena origen Regex Resultado
El coche tiene matrícula M8724RS M….RS Encuentra la primera ocurrencia de una cadena forma por "M", seguida de cuatro caracteres cualesquiera, y seguida de "RS".

Principio y final de cadenas

Es posible comprobar si una cadena empieza o acaba en un valor, utilizando los Metacaracteres ^ y $, respectivamente.

En algunos entornos es posible configurarlos para que aplique al principio y final de cada línea de texto existente en la cadena origen. A continuación se muestra un ejemplo correspondiente a .Net Framework: Regex.Match("string", "regex", RegexOptions.Multiline)

Si configuramos nuestro entorno en modo Multiline, podemos utilizar \A y \Z para buscar coincidencias en el principio de la cadena origen y en el final de la cadena origen, respectivamente.

Tanto $ como \Z buscan al final de la cadena, excluyendo en la búsqueda los caracteres de final de fichero (tanto\n como \r\n). Si fuera necesario, podríamos utilizar \z en sustitución de $ o de \Z, en busca de coincidencias exactas sobre el final de la cadena origen, incluyendo en dicha búsqueda de coincidencia incluso los caracteres de final de fichero.

A continuación se incluyen algunos ejemplos:

Cadena origen Regex Resultado
En un lugar de La Mancha ^En Existe coincidencia, ya que la cadena origen empieza por "En".
En un lugar de La Mancha cha$ Existe coincidencia, ya que la cadena origen finaliza en "cha".
50208617 ^\d+$ Existe coincidencia, ya que se está comprobado se todos los caracteres de la cadena origen, incluyendo el primero y el último, son dígitos.
En un lugar de La Mancha \AEn Existe coincidencia, ya que la cadena origen empieza por "En".
En un lugar de La Mancha cha\Z Existe coincidencia, ya que la cadena origen finaliza en "cha".

Disyunciones

Es posible realizar una búsqueda de coincidencia por varias Expresiones Regulares, utilizando el Metacaracter |. Es decir, dada una cadena origen, podríamos comprobar diferentes Expresiones Regulares sobre la misma.

Es determinante el orden de los valores especificados en la disyunción, es decir, primero se comprobará la coincidencia del primer valor especificado, a continuación del segundo, y así sucesivamente hasta comprobar la coincidencia de todos los valores de la disyunción. Evidentemente, en el momento en que se encuentra una coincidencia, el motor de Regex se detendrá.

Cadena origen Regex Resultado
Un año mariano. mar|playa Encuentra la primera ocurrencia de la cadena "mar".
https://www.guillesql.es http|https Encuentra la primera ocurrencia de la cadena "http" o de la cadena "https", y en este orden, por lo tanto tomará como coincidencia el texto "http", debido a este orden de interpretación.
https://www.guillesql.es https|http|ftp Encuentra la primera ocurrencia de la cadena "https" o de la cadena "http", o de la cadena "ftp", por lo tanto, tomará como coincidencia el texto "https", debido a este orden de interpretación.
Un año mariano. \b(mar|playa)\b No encuentra ninguna ocurrencia de la palabra "mar", ni de la palabra "playa". Ver más adelante Frontera de palabras.
Tanto monta, monta tanto, Isabel como Fernando. \b(Isabel|Fernando)\b Encuentra la primera ocurrencia de la palabra "Isabel" o de la palabra "Fernando", y en este orden, encontrado como coincidencia la cadena "Isabel". Ver más adelante Frontera de palabras.

Valores Opcionales

En ocasiones nos puede resultar útil poder realizar una búsqueda de forma opcional. Por ejemplo, si estamos buscando protocolos, podríamos estar interesados en encontrar tanto la cadena “http://”, como la cadena “https://”. Esto lo podríamos hacer con Disyunciones, como vimos anteriormente, pero también lo podemos hacer con Valores Opcionales, utilizando el Metacaracter ?.

Mediante el Metacaracter ? se puede especificar un valor opcional que se desea buscar, de tal modo, que primero se buscará por la cadena de búsqueda incluyendo el valor opcional, y si no se encuentra coincidencia, seguidamente se intentará la búsqueda sin incluir el valor opcional. Téngase en cuenta esto, ya que es relevante para el resultado de búsqueda.

Cadena origen Regex Resultado
https://guillesql.es http(s)?:// Encuentra la primera ocurrencia de la cadena "https://" o de la cadena "http://", y en este orden. Resulta equivalente a la Regex https://|http://, pero no es equivalente a la Regex http://|https://
Diciembre 2010 Dic(iembre)? 20(09|10) Encuentra la primera ocurrencia de las siguientes cadenas: "Diciembre 2009", "Diciembre 2010", "Dic 2009", "Dic 2010".
Diciembre 2010 Dic(iembre)? (20)?10 Encuentra la primera ocurrencia de las siguientes cadenas y en el siguiente orden: "Diciembre 2010", "Diciembre 10", "Dic 2010", "Dic 10".

Frontera de palabras

Es posible utilizar el delimitador de fronteras de palabras (\b), resultando de gran ayuda, cuando estamos buscando por alguna palabra, evitando que la búsqueda encuentre como coincidencia una ocurrencia de la cadena buscada que sea parte de una palabra.

Se considera Frontera de Palabras, al principio de la cadena, el final de la cadena, y los caracteres que no sean Word Characters (recordar \w, anteriormente en este mismo documento).

A continuación se incluyen algunos ejemplos:

Cadena origen Regex Resultado
Mañana va a llover en el sur. \bsur\b Encuentra la primera ocurrencia de la palabra "sur"
Mañana va a llover en el sureste. \bsur\b No encuentra ninguna ocurrencia de la palabra "sur".

Repeticiones

Otra tarea útil es la búsqueda de la repetición de un patrón de caracteres. Para ello, se pueden utilizar diferentes Metacaracteres: el asterisco (*) representa la repetición de cero o varias veces, el signo de sumar (+) representa la repetición de uno o varias veces, y además es posible encerrar entre llaves el número de repeticiones, utilizando la sintaxis {num} ó la sintaxis {min,max}. Téngase en cuenta, que en la sintaxis {min,max} es posible omitir el valor max, lo que se interpretará como un valor máximo de infinito.

Un caso interesante es la utilización del carácter comodín (.) con la repetición +, como se muestra más adelante en un ejemplo, debido a que el motor de Regex intentará ejecutar la repetición tantas veces como sea posible, lo cual, puede producir un resultado que no sea el deseado. Este comportamiento se puede cambiar incluyendo el Metacaracter ? después del + o del *, lo que producirá que el motor de Regex intente ejecutar la repetición el menor número de veces posibles.

Cadena origen Regex Resultado
Mi coche tiene matrícula M0237ZG \b[A-Z][0-9]{4}[A-Z]{2}\b Encuentra la primera ocurrencia de una palabra formada por una letra mayúscula, seguida de cuatro dígitos, y seguido de dos letras mayúsculas.
23 \b[1-9][0-9]{0,4}\b Encuentra una ocurrencia de una palabra consistente en un número entre 1 y 99999, sin separadores de millares ni decimales.
<b>hola</b> <[A-Za-z][A-Za-z0-9]*> Encuentra la primera ocurrencia de una cadena formada por el símbolo "<", seguida de una letra, seguida de una repetición de 0 o varias letras o números, y seguido por el símbolo ">". En particular encontrará <b>.
<b>hola</b> <[A-Za-z0-9]+> Encuentra la primera ocurrencia de una cadena formada por el símbolo "<",seguida de una repetición de una o varias letras o números, y seguido por el símbolo ">". En particular encontrará "<b>".
<b>hola</b> <.+> Esta Regex encontrará "<b>hola</b>", en lugar de "<b>", debido a la utilización del carácter comodín con la repetición +.
<b>hola</b> <.+?> Esta Regex encontrará "<b>", debido a la utilización del carácter comodín con la repetición + y el ?.
<b>hola</b> <[^>]+> Esta Regex encontrará "<b>", de una forma más efectiva que la Regex anterior (<[^>]+>), en lo relacionado con recursos del sistema necesarios.
<b>hola</b> <[^<>]+> Otra alternativa para encontrar "<b>".

Grupos y Referencias (Backreferences)

Es posible utilizar los Metacaracteres correspondientes a los paréntesis para crear un grupo (agrupar) una parte de una Expresión Regular, de tal modo, que puede aplicarse alguna operación sobre dicho grupo (ej: marcarlo como un valor opcional).

Al crear un grupo, se crea una referencia (Backreference) a la parte de la cadena sobre la que se está buscando y que presenta una coincidencia para la parte de la Regex correspondiente a dicho grupo. Dicha referencia (Backreference) almacena la parte de la cadena que produjo la coincidencia.

Por ejemplo, la Regex Dic(iembre)? se cumplirá tanto para la cadena Diciembre (el valor de la referencia se establecerá a "iembre") como para la cadena Dic (el valor de la referencia estará vacío), y siguiendo dicho orden de evaluación.

La utilización de referencias es costosa en recursos del sistema, siendo posible omitir la utilización de dichas referencias, utilizando una sintaxis como la que se muestra en el siguiente ejemplo: Dic(?:iembre)?

Dado que es posible crear múltiples grupos en una única Regular Expression, también es posible referenciar cada grupo, de tal modo que con \1 referenciaremos el primer grupo, con \2 el segundo, y así sucesivamente, pudiendo referenciarse cada grupo múltiples veces si fuera necesario. La importancia de esto, se encuentra en que el valor de dichas referencias es posible reutilizarlo, tanto en la propia Expresión Regular, como posteriormente (ej: al hacer un Regex.Replace). Un par de casos representativos:

  • Buscar un tag HTML. Primero buscamos el tag de inicio utilizando un grupo, y luego seleccionamos hasta el tag de fin, para lo cual nos apoyamos en el valor de la referencia (backreference).
  • Reemplazar las cadenas correspondientes a URLs por HyperLinks. Por ejemplo, utilizando el método Replace de la clase Regex en .Net Framework, se podría localizar las cadenas que parezcan ser URLs, y sustituirlas por el código HTML de un HyperLink, algo que puede resultar de utilidad en la construcción de un Foro Web.
Cadena origen Regex Resultado
Prueba con <b><i>tags</i></b>. <([A-Za-z][A-Za-z0-9]*)\b[^>]*>.*?</\1> Localiza una cadena formada por un tag de inicio, un tag de fin, y el contenido de su interior. En nuestro caso, la coincidencia será <b><i>tags</i></b>. Aunque a priori puede parecer que no, resulta de gran importancia la utilización de \b.
Prueba con <br><i>tags</i></b>. <([A-Za-z][A-Za-z0-9]*)[^>]*>.*?</\1> Similar al ejemplo anterior pero sin utilizar el \b. En este caso, la coincidencia será <br><i>tags</i></b>, mientras que si hubiésemos utilizado el \b, la coincidencia habría sido <i>tags</i>. El motivo de este comportamiento es la utilización de [^>]*, que ha permitido esta interpretación <(b)r><i>tags</i></(b)> como válida, y de aquí la necesidad del \b. El motor Regex primero intentó buscar </br>, falló, y reintentó con </b>.
Igualdad 23=23 (\d+)=\1 Encuentra como coincidencia 23=23
Igualdad 23=23 (\d)+=\1 No encuentra coincidencia. La abría encontrado si la cadena origen fuese por ejemplo 2=2
Esto es es una prueba \b(\w+)\s+\1\b Busca palabras repetidas, por ejemplo, con intención de buscar erratas en la redacción de texto. En nuestro caso, muestra como coincidencia "es es"

Búsquedas condicionales (Lookahead y Lookbehind)

Es posible realizar búsquedas condicionales (Lookahead y Lookbehind), como por ejemplo, buscar por un valor numérico sólo si está precediendo a un operador aritmético (Lookahead). Del mismo modo, también es posible, por ejemplo, buscar por un valor numérico sólo si está precedido por un operador aritmético (Lookbehind). Nótese que la parte condicional, no formará parte del resultado de coincidencia.

A continuación se incluyen algunos ejemplos:

Cadena origen Regex Resultado
Operaciones 22+1=23 \d+(?=[+\-*/=]) Busca por un valor numérico que esté precediendo a un operador aritmético (Positive Lookahead). En nuestro caso de ejemplo, mostrará como coincidencia el texto 22.
Operaciones 22+1=23 \d+(?![+\-*/=]) Busca por un valor numérico que no esté precediendo a un operador aritmético (Negative Lookahead). En nuestro caso de ejemplo, mostrará como coincidencia el texto 2, correspondiente al primer 2 del texto 22 (si este número tuviese sólo una cifra, la coincidencia habría sido el texto 23)
Operaciones 22+1=23 (?<=[+\-*/=])\d+ Busca por un valor numérico que esté precedido por un operador aritmético (Positive Lookbehind). En nuestro caso de ejemplo, mostrará como coincidencia el texto 1.
Operaciones 22+1=23 (?<![+\-*/=])\d+ Busca por un valor numérico que no esté precedido por un operador aritmético (Negative Lookbehind). En nuestro caso de ejemplo, mostrará como coincidencia el texto 22.

 

 




Miembros de
Miembros de GITCA (Global IT Community Association)

Menu de Usuario
  Iniciar Sesión
  Registrarse
  Restablecer Contraseña
  Ventajas de Registrarse

Acerca de
  Contigo desde Oct 2007
  771 usuarios registrados
  86146 pageloads/mes
  Ranking Alexa 498160

Social Networks
Sigue a Portal GuilleSQL en Linkedin !!
Sigue a Portal GuilleSQL en Twitter !!



Archivo

Marzo de 2019 (1)
Octubre de 2018 (1)
Julio de 2018 (1)
Junio de 2018 (4)
Mayo de 2018 (5)
Abril de 2018 (3)
Marzo de 2018 (2)
Febrero de 2018 (7)
Enero de 2018 (1)
Diciembre de 2017 (15)
Noviembre de 2017 (7)
Junio de 2017 (3)
Mayo de 2017 (1)
Marzo de 2017 (3)
Enero de 2017 (4)
Junio de 2016 (1)
Mayo de 2016 (2)
Abril de 2016 (2)
Septiembre de 2015 (2)
Agosto de 2015 (2)
Junio de 2015 (10)
Mayo de 2015 (4)
Abril de 2015 (8)
Marzo de 2015 (11)
Octubre de 2014 (3)
Septiembre de 2014 (7)
Agosto de 2014 (5)
Julio de 2014 (2)
Mayo de 2014 (4)
Abril de 2014 (4)
Marzo de 2014 (4)
Febrero de 2014 (1)
Enero de 2014 (5)
Diciembre de 2013 (8)
Noviembre de 2013 (2)
Octubre de 2013 (7)
Septiembre de 2013 (6)
Agosto de 2013 (1)
Julio de 2013 (6)
Junio de 2013 (11)
Mayo de 2013 (7)
Abril de 2013 (6)
Febrero de 2013 (5)
Enero de 2013 (7)
Diciembre de 2012 (12)
Noviembre de 2012 (13)
Octubre de 2012 (5)
Septiembre de 2012 (3)
Agosto de 2012 (6)
Julio de 2012 (4)
Junio de 2012 (1)
Mayo de 2012 (2)
Abril de 2012 (7)
Marzo de 2012 (16)
Febrero de 2012 (9)
Enero de 2012 (5)
Diciembre de 2011 (10)
Noviembre de 2011 (10)
Octubre de 2011 (4)
Septiembre de 2011 (5)
Agosto de 2011 (2)
Julio de 2011 (2)
Junio de 2011 (4)
Mayo de 2011 (2)
Abril de 2011 (6)
Marzo de 2011 (4)
Febrero de 2011 (10)
Enero de 2011 (5)
Diciembre de 2010 (6)
Noviembre de 2010 (4)
Octubre de 2010 (8)
Septiembre de 2010 (4)
Agosto de 2010 (1)
Julio de 2010 (3)
Mayo de 2010 (5)
Abril de 2010 (6)
Marzo de 2010 (8)
Febrero de 2010 (3)
Enero de 2010 (1)
Diciembre de 2009 (9)
Noviembre de 2009 (14)
Octubre de 2009 (2)
Septiembre de 2009 (8)
Agosto de 2009 (2)
Julio de 2009 (10)
Junio de 2009 (9)
Mayo de 2009 (10)
Abril de 2009 (9)
Marzo de 2009 (3)
Febrero de 2009 (2)
Enero de 2009 (3)
Noviembre de 2008 (2)
Octubre de 2008 (2)
Septiembre de 2008 (2)
Agosto de 2008 (5)
Julio de 2008 (5)
Junio de 2008 (1)
Mayo de 2008 (3)
Abril de 2008 (2)
Marzo de 2008 (2)
Febrero de 2008 (2)
Enero de 2008 (5)
Noviembre de 2007 (2)
Octubre de 2007 (2)






Copyright © 2007 GuilleSQL, todos los derechos reservados.