¿Como encuentro y reemplazo texto de una cadena? | Regex | Expresiones regulares | Programación

 imagen-ilustrativa-regex

Ahora si ¡Vamos con el ejemplo!


Voy a programar en PHP pero ustedes pueden utilizar otro lenguaje que tenga librerías regex.

Planteo el siguiente escenario. Tengo una cadena de texto de HTML y quiero extraer con REGEX lo que se encuentra dentro de una determinada etiqueta:

Mi cadena de texto es: <div>Hola Mundo</div>

Con la función preg_replace de PHP, voy a extraer el texto y con print voy a imprimir la variable que me convenga. El código quedaría así:

<!php
$texto = "<div>Hola Mundo</div>";
$regex = "/\<div\>(.*)\<\/div\>";
preg_replace($regex, '$0 $1', $texto);
print $0; //Va a imprimir <div>Hola Mundo</div>
print $1; // va a imprimir Hola Mundo
!>

Explico el REGEX: toda expresión regex está contenida entre barras /expresión regex/. Todo carácter especial, como "<", "/" o "salto de linearegex no lo reconoce, entonces hay que colocar antes del carácter una barra invertida "\". Agrego un ejemplo: cuando tenemos un salto de linea se coloca "\n".

Por último la expresión "(.*)" significa que coincida con cualquier carácter. Por ejemplo si solo queremos que coincida con un números del 0 al 9 seria "[0-9]". Sí queremos que solo coincida con un número del 0 al 9 de 3 cifras seria "[0-9]{3}".

Ahora un ejemplo más complejo:

Planteo un archivo XML que quiero extraer datos y imprimirlos en una tabla XML con PHP. El código seria:

<!php
$texto = "<resultado>
<determinacion>FOLÍCULO ESTIMULANTE basal</determinacion>
<valor>7.7</valor>
<tarjeta>TAR8</tarjeta>
<ordentarjeta>3</ordentarjeta>
<ordendeterminaciontarjeta>417</ordendeterminaciontarjeta>
<observaciones></observaciones>
<unidad>mUI/ml</unidad>
<metodo>EQLIA</metodo>
<referencia><![CDATA[faz folicular  3.0 - 12.0 mUI/ml]]></referencia>
<validado>SI</validado>
</resultado>";

$regex = "/\<resultado\>\n\<determinacion\>(.+)\<\/determinacion\>\n(\<valor\>(.+)\<\/valor\>|\<valor\/>)\n(\<tarjeta\>(.+)\<\/tarjeta\>|\<tarjeta\/>)\n(\<ordentarjeta\>(.+)\<\/ordentarjeta\>|\<ordentarjeta\/\>)\n(\<ordendeterminaciontarjeta\>(.+)\<\/ordendeterminaciontarjeta\>|\<ordendeterminaciontarjeta\/\>)\n(\<observaciones\>(.+)\<\/observaciones\>|\<observaciones\/\>)\n(\<unidad\>(.+)\<\/unidad\>|\<unidad\/\>)\n(\<metodo\>(.+)\<\/metodo\>|\<metodo\/\>)\n(\<referencia\>\<\!\[CDATA\[(.+)\]\]\>\<\/referencia\>|\<referencia\>\<\!\[CDATA\[\]\]\>\<\/referencia\>)\n\<validado\>(.+)\<\/validado\>/";

preg_replace($regex, '$1 $3 $15 $11 $17', $texto);

print "<table><tr><td>$1</br>$15</td><td>$3 $13</td><td>$17</td><td>$11</td></tr></table>";
!>

Así de sencillo, aclaro un par de cosas: en este ejemplo uso en REGEX el caracter "|" que significa "o", en programación logica seria "OR". Quiere decir que coincide una cadena de texto o otra. También uso "(" y ")" que sirve para agrupar.

Bien fin. Les dejo los códigos de ejemplo en GitLab

Plus: un poco de teoría

Regex o expresiones regulares: la manera más sencilla de describir secuencias de caracteres

La búsqueda de caracteres o secuencias concretas de caracteres en documentos forma parte de las tareas estándar y recurrentes de la tecnología de la información. Por lo general, el objetivo es modificar o sustituir fragmentos de texto o líneas de código, cuya complejidad aumenta en función de las veces que la secuencia de caracteres aparece en el documento. En la década de 1950 se encontró una solución basada en las lenguas formales de la informática teórica que sigue presente en el desarrollo actual de software y que permite simplificar estas tareas repetitivas mediante el uso de las denominadas expresiones regulares (en inglés, regular expressions).

¿Cómo funciona una expresión regular?

Una expresión regular puede estar formada, o bien exclusivamente por caracteres normales (como abc), o bien por una combinación de caracteres normales y metacaracteres (como ab*c). Los metacaracteres describen ciertas construcciones o disposiciones de caracteres: por ejemplo, si un carácter debe estar en el inicio de la línea o si un carácter solo debe o puede aparecer exactamente una vez, más veces o menos. Ambos ejemplos de expresiones regulares funcionan, por ejemplo, de la siguiente manera:

abc. El patrón regex sencillo abc requiere una coincidencia exacta. Por tanto, se buscarán cadenas de caracteres que no solo contengan los caracteres “abc”, sino que también aparezcan en ese orden. Una pregunta como “¿Conoces la plaza ABC?” ofrece la coincidencia buscada por esta expresión.

ab*c. Las expresiones regulares con caracteres especiales funcionan de manera diferente, ya que no solo se buscarán coincidencias exactas, si no también escenarios especiales. En este caso, el asterisco hace que la búsqueda se centre en cadenas de caracteres que empiecen por la letra “a” y que terminen por la letra “c” y entremedias cuenten con cualquier número de caracteres “b”. Así se mostrará como coincidencia tanto “abc”, como la cadena de caracteres “abbbbc” y “cbbabbcba”.


Expresiones regulares de un elemento

La forma regex más sencilla es un patrón de búsqueda que tan solo prevé un único elemento como resultado. Este tipo de expresión regular de un elemento puede, por ejemplo, definirse sin problemas usando una clase de caracteres, siempre y cuando no se esté buscando un elemento concreto. La siguiente expresión permite opcionalmente los dígitos “1”, “2”, “3”, “4”, “5”, “6” o “7” como posible resultado:

[1234567]

En este caso, los números son directamente consecutivos, por lo que también se permite la siguiente grafía simplificada:

[1-7]

En caso de que la expresión regular deba modificarse para excluir de la búsqueda el dígito “4”, también se puede utilizar la variante más simple con el signo menos:

[1-35-7]

Nota: Los caracteres de un patrón regex no se separan con espacios.

Expresiones regulares de varios elementos

En el caso de las expresiones regulares de varios elementos, también se puede trabajar con clases de caracteres para permitir resultados diferentes. Si la expresión tiene que incluir, por ejemplo, dos elementos para los que se pueden esperar diferentes resultados, entonces basta con colocar dos clases de caracteres una después de la otra:

[1-7][a-c]

Como primer elemento, ha de aparecer un número de entre el “1” y el “7”, seguido de una letra “a”, “b” o “c”. Recordamos que aquí las minúsculas son obligatorias. Sin profundizar en los modificadores, con este pequeño ajuste de la expresión puedes incluir las mayúsculas:

[1-7][a-cA-C]

Expresiones regulares con elementos opcionales

Al margen de si se buscan varios elementos en una única expresión regular o con ayuda de varios grupos de caracteres, es posible que determinados elementos solo se deban o puedan incluir en determinadas condiciones. Este puede ser, por ejemplo, el caso de una expresión regular que debe filtrar todos los números de casa de las direcciones. En los casos en los que el número de casa sea un único dígito, puede coincidir con algunos resultados en los que el número está compuesto por dos o incluso tres dígitos. Además, hay direcciones en las que el número de casa incluye también una letra. Para abarcar todas estas posibles combinaciones, puedes usar las siguientes instrucciones regex:

[1-9][0-9]?[0-9]?[a-z]?

El único elemento obligatorio de este patrón de búsqueda es un número del “1” al “9”. Pueden estar seguidos opcionalmente tanto por dos dígitos del “0” al “9”, como por una letra cualquiera. Todas las opciones posibles se marcan con el signo de interrogación visto arriba.

Aunque la construcción de números de tres dígitos con letras adicionales resulta bastante clara, los números de hasta diez dígitos tienen un aspecto bastante diferente. En este caso recomendamos utilizar las llaves tal y como se muestra en la siguiente expresión regular:

[1-9][0-9]{0,9}

Al igual que en el ejemplo anterior, en primer lugar, se requiere un número del “1” al “9” que puede estar seguido de ninguno o de hasta nueve dígitos del “0” al “9”, de modo que el resultado de la búsqueda pueda estar formado por hasta diez dígitos.

Expresión regular con una cantidad aleatoria de repeticiones

En los ejemplos vistos hasta ahora para expresiones de uno o varios elementos, se conocían las cantidades mínima y máxima de caracteres. Sin embargo, hay otros escenarios en los que no se puede determinar de antemano con exactitud la cantidad de caracteres de una regex. Los parámetros necesarios son el asterisco (*) y el signo más (+), los cuales permiten una cantidad cualquiera de repeticiones de un carácter, una clase o grupos de caracteres. Se pueden registrar todas las cadenas de caracteres que tengan una cantidad cualquiera de dígitos (también “cero”), por ejemplo, con la siguiente expresión regular:

[0-9]*

Esto también es válido para la búsqueda de una combinación concreta de caracteres en la que uno (o varios) caracteres pueden aparecer con una frecuencia cualquiera, tal y como se muestra en el siguiente ejemplo:

ab*

En este caso, los resultados son las palabras “arrancar” y también “abrir”. En caso de que se deba ignorar el primer resultado o si el carácter especificado debe aparecer como mínimo una vez, entonces debe utilizarse el signo más:

ab+

Negar clases de caracteres

Si se desean utilizar expresiones regulares con clases de caracteres que equivalen a uno o varios caracteres, pero al mismo tiempo se desea descartar como resultado a uno o varios caracteres determinados, entonces se necesita utilizar la negación “^” (acento circunflejo). Este signo se sitúa siempre dentro de los corchetes de una clase de caracteres, por lo que su validez se limita a los mismos. La siguiente instrucción es un buen ejemplo de una clase de caracteres en negación:

c[^o]sa

En este caso, el segundo carácter puede ser un carácter cualquiera excepto “o”, por lo que la palabra “casa” cumple con los criterios de coincidencia. Sin embargo, la palabra “cosa” no lo cumple.

Marcador de posición

Las expresiones regulares también permiten trabajar con marcadores de posición, los cuales equivalen a uno, varios o incluso ningún carácter (dependiendo del metacarácter utilizado) dentro de un patrón de búsqueda. El marcador de posición se genera mediante un punto combinado con el carácter especial citado antes para repeticiones, siempre y cuando se desee obtener un resultado de más de un único carácter. Este tipo de expresiones regulares permite, por ejemplo, buscar en una base de datos a una persona que, aunque se conoce por su nombre y apellidos, no se tiene la certeza de si se ha introducido incluyendo un segundo nombre:

Juan.*Apellido

En este caso, los resultados pueden ser tanto “Juan Antonio Apellido” (o cualquier otra combinación de segundo nombre) como “Juan A. Apellido” o “Juan Apellido”. Si solo deben tenerse en cuenta las variantes con un segundo nombre, entonces deberá utilizarse un signo más en lugar del asterisco:

Juan.+Apellido

Un buen ejemplo de uso práctico de un marcador de posición para un único carácter es el siguiente patrón de búsqueda, en el que las coincidencias pueden ser tanto “casa” como “cosa”:

c.sa

Alternativas | OR

Las expresiones regulares también pueden formularse de tal manera que se ofrezcan dos o más coincidencias alternativas. La alternativa tiene validez usando como separación una barra vertical, tal y como se muestra en el siguiente ejemplo:

casa|cosa

En este caso, tanto “casa” como “cosa” ofrecerán una coincidencia.

Las alternativas también pueden formularse dentro de palabras o secuencias de caracteres mediante el uso de grupos:

(Lun|Mart|Miércol|Juev|Viern)es|Sábado|Domingo

En este ejemplo, cada uno de los días de la semana pueden ser un resultado pues, gracias a la agrupación mediante paréntesis, todos los días de la semana que acaban en “es” se registran correctamente, incluso si se usan de forma abreviada.

Grupos

Los grupos de caracteres, como los del apartado anterior, son considerados clases de caracteres por los elementos estructurales de las expresiones regulares. Pueden definirse con un par de paréntesis y equivalen básicamente a un patrón compuesto por uno o varios caracteres. En el sentido estricto de la palabra, cada regex es un grupo, pero en este caso se obvia la caracterización mediante paréntesis. Dentro de las expresiones, los grupos permiten aplicar operadores tales como el delimitador o el signo de repetición (signo más o asterisco) en una expresión parcial específica:

ab(cd)+

En este caso, la repetición aleatoria que se busca también será válida para el grupo de caracteres “cd” pero, si se prescinde de los paréntesis, solo será válida para “d”. Dentro de una regex no hay límites para la cantidad de grupos incluidos.

Anidamientos

Una expresión regular no solo puede albergar una cantidad cualquiera de grupos, sino que también permite anidar tantos grupos como se desee para expresar designaciones complejas entre caracteres individuales y caracteres especiales sin necesidad de usar cadenas de caracteres excesivamente largas. Un ejemplo es el siguiente patrón regex, con el cual se pueden obtener como posible resultado los cuatro modelos de automóvil “VW Golf”, “VW Polo”, “Fiat Punto” o “Fiat Panda”:

(VW (Golf|Polo)|Fiat (Punto|Panda))

Límite de palabra

Cuando, al aplicar una expresión regular, deban tenerse en cuenta los límites de palabra, esto es, el inicio o el final de una secuencia alfanumérica, entonces se deberán especificar mediante el uso de metacaracteres. Muchos lenguajes utilizan para esto la combinación “\b”, la cual se puede anteponer, agregar o posponer al patrón de búsqueda.

La primera variante determina que la secuencia de búsqueda esté al principio de la palabra:

\bcaso

Una coincidencia para esta expresión regular es, por ejemplo, la palabra “casona”. Por el contrario, la palabra “acaso” se excluye de los resultados debido a que el carácter que se ha buscado tiene delante la letra “a”. Para el caso contrario, se puede utilizar la segunda variante y agregar el carácter especial:

caso\b

Con la tercera opción, ambos límites de palabra se convierten en requisito imprescindible; en el caso del ejemplo utilizado, el único resultado posible es la palabra “caso”:

\bcaso\b

Quitar metasignificado de caracteres especiales

En el apartado anterior, la barra diagonal inversa garantiza que la “b” colocada después no se va a utilizar como letra, sino como metacarácter. Si se combina con caracteres considerados por defecto como uno de los caracteres especiales sintácticos regex, entonces tendrá exactamente el efecto opuesto: el carácter se considerará como un literal común. Gracias a esta opción, también se puede buscar sin problemas una fecha concreta usando una expresión regular:

11\.10\.2019

En este caso, la fecha “11.10.2019” es la única cadena de caracteres que coincide con los criterios de búsqueda especificados. Si no se coloca la barra diagonal inversa, los dos puntos se considerarían marcadores de posición para un carácter cualquiera, por lo que también se ofrecerían resultados del tipo “1101092019” o “11a10b2019”.

“Moderar” expresiones regulares ambiciosas

El uso de cuantificadores (“?”, “+”, “*”, “{}”) garantiza por defecto que una expresión sea “ambiciosa” y que, por tanto, busque la mayor coincidencia posible. Como este comportamiento no siempre es deseable, los cuantificadores se pueden especificar en una expresión regular de tal manera que se modere esa “ambición”. Este proceso de modificación se muestra claramente en el siguiente ejemplo:

A.*B

Si se aplica en la secuencia de caracteres “ABCDEB”, esta expresión no para la búsqueda tras “AB”, sino que engloba como resultado toda la secuencia de caracteres. Si, por el contrario, la búsqueda se debe cancelar justo tras la primera “B”, entonces se necesita la modificación indicada. Para ello, en muchas de las lenguas (entre otras Perl, Tcl, HTML) se coloca detrás una marca de interrogación:

A.*?B

Como alternativa, la expresión original también se puede sustituir por la siguiente expresión equivalente y “no ambiciosa”, para así obtener el mismo resultado:

A[^B]*B




Tabla machete

Caracteres especiales regex de sintaxisFunción
[]Los corchetes identifican a una clase de caracteres que siempre representa a un único carácter en un patrón de búsqueda.
()Los paréntesis identifican un grupo de caracteres formado por uno o varios caracteres y que pueden operarse unos dentro de los otros.
-Funciona a modo de especificación del área (de […] hasta […]) cuando se sitúa entre dos caracteres normales.
^Limita la búsqueda al inicio de una línea (otra función: elemento de negación en clases de caracteres).
$Limita la búsqueda al final de una línea.
.Equivale a cualquier carácter.
*El número del carácter, de la clase o del grupo situado antes del asterisco puede ser aleatorio (cero incluido).
+El carácter, la clase o el grupo antes de un signo más debe aparecer como mínimo una vez.
?El carácter, la clase o el grupo antes del signo de interrogación es opcional y puede aparecer como máximo una vez.
{n}El carácter, la clase o el grupo anteriores aparecen exactamente n veces.
{n,m}El carácter, la clase o el grupo anteriores aparecen como mínimo n veces y como máximo m veces.
{n,}El carácter, la clase o el grupo anteriores aparecen como mínimo n veces o con frecuencia.
\bTiene en cuenta el límite de palabra durante la búsqueda.
\BIgnora el límite de palabra durante la búsqueda.
\dCualquier dígito; abreviatura para la clase de caracteres [0-9].
\DCualquier no dígito; abreviatura para la clase de caracteres [^0-9].
\wCualquier carácter alfanumérico; abreviatura para la clase de caracteres [a-zA-Z_0-9].
\WCualquier carácter no alfanumérico; abreviatura para la clase de caracteres [^\w].

/*----------------------------------------------------------------------------------------------------*/


Si te gustó comentá y compartí

Donar: Agradecemos de antemano su generosidad y apoyo continuo a la educación y a la investigación.


Fuentes: 

https://www.ionos.es/digitalguide/paginas-web/creacion-de-paginas-web/regex/




Comentarios

Entradas populares