expresiones regulares

Resolución de los ejercicios del taller de expresiones regulares en WordCamp Sevilla

En este post voy a tratar de explicar la resolución a los 5 ejercicios que propuse en el taller de expresiones regulares de la WordCamp Sevilla para desarrolladores.

Estos ejemplos son únicamente con fines didácticos, donde se contemplan diferentes casuísticas y variaciones típicas que pueden presentarse a la hora de enfrentarnos a buscar un patrón en un texto.

Extrae los shortcodes para su eliminación

Como comenté en el taller, en WordPress podríamos utilizar funciones auxiliares para tal fin, simplemente es un ejercicio con fines didácticos.

Puedes practicarlo en el siguiente enlace de regex101. En el texto hay dos shortcodes, y necesitarás una expresión que contemple extraer los mismos teniendo en cuenta que uno está en una línea y el otro en dos.

La expresión regular sería la siguiente: /\[my_shortcode(?:.*)[^\]]*\[\/my_shortcode\]/g. Y su explicación:

  • \[ => Buscamos literalmente el carácter apertura de corchete. Para ello necesitamos escaparlo con la contrabarra
  • my_shortcode => Buscamos literalmente la cadena «my_shortcode»
  • (?:.*) => Agrupamos cualquier carácter (el punto es el comodín) cero o más veces (lo indicamos con el asterisco). Indicamos que no queremos capturar el grupo en la salida con la interrogación dos puntos. Es decir, con el punto asterisco seleccionamos todos los caracteres (cualquiera que sea) que vengan después de «my_shortcode»
  • [^\]]* => Como antes hemos indicado que busque cualquier carácter, y después vamos a querer buscar el cierre del shortcode, ahora indicamos que sea cualquier carácter cero o más veces que no sea el cierre del corchete.
  • \[\/my_shortcode\] => Por último, buscamos literalmente el cierre del shortcode, escapando los caracteres de los corchetes y la barra para que los busque literalmente

Valida un código postal español

Lo primero que nos puede venir a la mente es validar que sean 5 números. Cualquier otra cosa no tendría el formato de un código postal español.

Pero estaríamos obviando otra serie de casuísticas como que el código postal «más alto» debería ser 52999. Es decir, no existe un código postal en España que empiece por 53 o superior.

Por eso comentaba en la charla que la dificultad de las expresiones regulares radica en contemplar todos los escenarios.

Puedes practicarlo en el siguiente enlace de regex101. La expresión regular sería la siguiente /(?:[0-4][0-9]|5[0-2])[0-9]{3}/g. Y su explicación:

  • (?: => No vamos a capturar este grupo
  • [0-4][0-9]|5[0-2] => Tenemos un pipe, equivalente a un OR, donde buscamos los dos primeros dígitos: Y puede ser o uno del 0 al 4 seguido de otro del 0 al 9 (lo que nos daría la horquilla entre 00 y 49; o un 5 (fijo) seguido de otro dígito comprendido entre 0 y 2. Es decir: desde el 50 hasta el 52. Cualquier otra cosa no coincidirá y no encontrará el patrón
  • ) => Cierre del grupo de no captura
  • [0-9]{3} => Buscamos exactamente 3 veces un dígito comprendido entre 0 y 9. Unidos a los dos de antes, conformará los 5 dígitos de un código postal

Añade el atributo rel=”nofollow” a los enlaces

Las expresiones regulares también pueden utilizarse para realizar sustituciones. En este ejemplo vamos a buscar enlaces y añadir el atributo rel=»nofollow».

La «complejidad» en este ejemplo es que los enlaces están contribuidos de manera distinta: unos con espacios entre el igual y las comillas, unos con comillas simples, otro con dobles….

Puedes practicarlo en el siguiente enlace de regex101. La expresión regular sería la siguiente /(href\s*=\s*[«‘][^»‘]*[«‘])/g. Y su explicación:

  • href => Buscamos literalmente el texto «href»
  • \s* => Buscamos el carácter espacio (\s) cero o más veces. Es decir, que puede haber espacio o no, incluso varios espacios antes del igual
  • = => Buscamos literalmente el caracter «igual»
  • \s* => Buscamos el carácter espacio (\s) cero o más veces. Es decir, que puede haber espacio o no, incluso varios espacios después del igual
  • [«‘] => Buscamos un carácter de los que se encuentran dentro del conjunto de caracteres, en este caso comilla simple o doble
  • [^»‘]* => Buscamos cualquier carácter que no esté presente en el conjunto de caracteres, en este caso comilla simple o doble, cero o más veces. Es decir, cualquier carácter tantas veces como sea excepto la comilla que cerrará nuestro enlace
  • [«‘] => Ahora sí, buscamos el cierre de nuestro enlace, que no será más que buscar de nuevo un carácter de los que se encuentran dentro del conjunto de caracteres, en este caso comilla simple o doble

Con esto tendremos la primera parte, para realizar la sustitución, únicamente tendríamos que sustituirlo por si mismo (para esto hacemos referencia al grupo con \1) concatenado el texto que queremos añadir, en este caso rel=»nofollow».

Pego a continuación el código generado por regex101 para que se entienda mejor:

<?php

$re = '/(href\s*=\s*["\'][^"\']*["\'])/';
$str = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In tempor sed elit at luctus. Phasellus a commodo nisi.

<a href="https://mydomain.com/link1/" target="_blank">Link 1</a>

In hac habitasse platea dictumst. Etiam laoreet rhoncus rhoncus. Sed hendrerit nisl posuere maximus aliquam.

<a href = "https://mydomain.com/link2/">Link 2</a>

Quisque eleifend arcu quis lacinia efficitur. Nam lobortis nibh purus, sodales ultricies lacus luctus eget.

<a href =\'https://mydomain.com/link3/\' title=\'link title\'>Link 3</a>';
$subst = '\\1 rel="nofollow"';

$result = preg_replace($re, $subst, $str);

echo "The result of the substitution is ".$result;

Localiza las URLs de los enlaces que aparecen en el siguiente texto

En este ejemplo vamos a localizar las URLs de los enlaces que aparecen en un texto. Ojocuidao que hay 5 enlaces, pero uno de ellos es un mailto (que no nos interesa), y de los otros 4, algunos están con comillas simples, otros con dobles, unos con http, otros con https, otros son agnósticos, y en otro aparece el atributo title antes del href.

Como ves, parece una tontería pero hay mucha casuística diferente en este ejemplo. Puedes practicarlo en el siguiente enlace de regex101. La expresión regular sería la siguiente /<a[^>]+href=[«‘](?<url>(?:https?:)?\/\/.*?)[«‘]/g. Y su explicación:

  • <a => Buscamos literalmente la apertura de la etiqueta «a»
  • [^>]+ => A continuación cualquier carácter que no sea un cierre de etiqueta, una o más veces.
  • href= => Buscamos literalmente la cadena «href=»
  • [«‘] => Buscamos la apertura de las comillas del enlace, que puede ser simple o doble
  • (?<url> => Abrimos un grupo de captura y lo nombramos «url». Esto será devuelto con esa key en el resultado del match
  • (?:https?:)? =>Abrimos un grupo de no captura (?:) donde buscamos http, despues una «s» (al ir sucedida de una interrogación indica que puede estar cero o una vez), a continuación los «:» y todo el grupo sucedido de otra interrogación indica que puede ir cero o una vez. De este modo encontraremos enlaces con http, con https y agnósticos
  • \/\/ => Buscamos las dos barras de la URL, deben ir escapadas
  • .*? => Buscamos cualquier carácter y lo hacemos «lazy» para acotar el ámbito
  • ) => Cerramos el grupo
  • [«‘] => Buscamos el cierre del enlace, que puede ser comilla simple o doble

Comprueba la fortaleza de un password

Vamos a comprobar la fortaleza de una contraseña teniendo en cuenta que debe tener entre 8 y 12 caracteres, y al menos una mayúscula, una minúscula, y un dígito.

Puedes practicarlo en el siguiente enlace de regex101. La expresión regular sería la siguiente /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,12}$/gm. Y su explicación:

  • ^ => Inicio de la cadena
  • (?=.*[a-z]) => Futuro positivo (no se captura). Buscamos cualquier carácter y al menos una letra contenida en el rango de caracteres (minúscula)
  • (?=.*[A-Z]) => Futuro positivo (no se captura). Buscamos cualquier carácter y al menos una letra contenida en el rango de caracteres (mayúscula)
  • (?=.*\d) => Futuro positivo (no se captura). Buscamos cualquier caracter y al menos un dígito
  • [a-zA-Z\d] => Buscamos dentro de un conjunto de caracteres donde puede haber mayúsculas, minúsculas o dígitos
  • {8,12} => Lo anterior, entre 8 y 12 veces
  • $ => Fin de la cadena

En este caso, añadimos el flag «m» (multiline), ya que estamos buscando una cadena con inicio y fin de línea.

Pues hasta aquí los ejemplos. Espero que hayas intentado hacerlo por tu cuenta y hayas aprendido a tener en cuenta multitud de posibilidades para que la expresión regular sea más fina y no devuelva resultados inesperados.

¿Te ha resultado útil esta información? 🍺

Si este post te ha resuelto un problema, invítame a un café o a una cerveza. Con este pequeño gesto me animas a seguir escribiendo.

Comentarios

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *:

  • El fin del tratamiento es únicamente la moderación de comentarios para evitar spam
  • La legitimación es tu consentimiento al comentar
  • No se comunicará ningún dato a terceros salvo por obligación legal
  • Tienes derecho al acceso, rectificación y eliminación de los comentarios