Ubuntu

Conceptos básicos de las expresiones regulares

Conceptos básicos de las expresiones regulares

Este es un repost directo de el artículo original en mi blog.

En mi equipo realizamos “clases magistrales” cada dos semanas, en las que alguien del equipo presenta un tema al resto del equipo.

Este artículo es básicamente el contenido de la clase sobre expresiones regulares (también conocido como regex) que di recientemente.

Es una introducción a los conceptos básicos de las expresiones regulares. Allí son muchos me gusta eso, pero esto es mío.

¿Qué es una expresión regular (o regex)?

Wikipedia define expresiones regulares como:

«Una secuencia de caracteres que definen un patrón de búsqueda»

Están disponibles básicamente en todos los lenguajes de programación, y probablemente los encontrará más comúnmente utilizados para coincidencias de cadenas en condicionales que son demasiado complicados para comparaciones lógicas simples (como «o», «y», «en»).

Un par de ejemplos de expresiones regulares para comenzar:

[ -~] Cualquier carácter ASCII
(Los caracteres ASCII se encuentran entre el espacio y «~»)
^[a-z0-9_-]{3,15}$ Nombres de usuario entre 3 y 15 caracteres

Cuando usar regex

Utilice las expresiones regulares con precaución. La complejidad de las expresiones regulares tiene un costo.

Evite codificar en expresiones regulares si puede

‘Algunas personas, cuando se enfrentan a un problema, piensan «Lo sé, usaré expresiones regulares». Ahora ellos tienen dos problemas. – Jamie Zawinski

En programación, solo use expresiones regulares como último recurso. No resuelva problemas importantes con expresiones regulares.

  • regex es caro
    – regex es a menudo la parte de un programa que consume más CPU. Y una expresión regular que no coincida puede ser incluso más costosa de verificar que una que coincida.
  • regex es codicioso: es extremadamente fácil hacer coincidir mucho más de lo previsto, lo que genera errores. Varias veces hemos tenido problemas con las expresiones regulares que son demasiado codiciosas, lo que causa problemas en nuestros sitios.
  • regex es opaco
    – Incluso las personas que conocen bien las expresiones regulares tardarán un tiempo en seleccionar una nueva cadena de expresiones regulares y es probable que cometan errores. Esto tiene un costo enorme para el mantenimiento del proyecto a largo plazo. (Mira este asombroso regex para direcciones de correo electrónico RFC822)

Siempre trate de estar al tanto de todas las funciones de idioma a su disposición para operar y verificar cadenas, que podrían ayudarlo a evitar expresiones regulares. En Python, por ejemplo, el in palabra clave, el poderoso [] indexación y métodos de cadena como contains y startswith (que se puede alimentar con cadenas de tuplas para múltiples valores) se puede combinar de manera muy efectiva.

Más importante aún, las expresiones regulares no deben usarse para analizando instrumentos de cuerda. En su lugar, debería utilizar o escribir un analizador a medida. Por ejemplo, no se puede analizar HTML con expresiones regulares (en Python, use Hermosa Sopa; en JavaScript, use el DOM).

Cuando codificar en expresiones regulares

Por supuesto, hay ocasiones en las que las expresiones regulares pueden o deben usarse en programas:

  • Cuando ya exista y tengas que mantenerlo (aunque si puedes eliminarlo, deberías hacerlo)
  • Validación de cadenas, donde no hay otra opción
  • Manipulación de cadenas (sustitución), donde no hay otra opción

Si está escribiendo algo más que la expresión regular más básica, es poco probable que los mantenedores puedan comprender su expresión regular fácilmente, por lo que es posible que desees considerar agregar comentarios liberales. P.ej esto en Python:

>>> pattern = """
^                   # beginning of string
M{0,4}              # thousands - 0 to 4 M's
(CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
                    #            or 500-800 (D, followed by 0 to 3 C's)
(XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
                    #        or 50-80 (L, followed by 0 to 3 X's)
(IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
                    #        or 5-8 (V, followed by 0 to 3 I's)
$                   # end of string
"""
>>> re.search(pattern, 'M', re.VERBOSE) 

Otros grandes usos de las expresiones regulares

Las expresiones regulares pueden ser extremadamente poderosas para resolver rápidamente problemas por sí mismo, donde el mantenimiento futuro no es una preocupación. P.ej:

  • Grep (o Ripgrep), Sed, Menos y otras herramientas de línea de comandos
  • En editores (p. Ej. VSCode), para reformatear el texto rápidamente

También vale la pena aprovechar las oportunidades para usar expresiones regulares de estas formas para practicar sus habilidades de expresiones regulares.

Por ejemplo, recientemente utilicé la siguiente sustitución de expresiones regulares en VSCode para formatear un volcado de texto en un formato de tabla:

Cómo usar regex

Tenga en cuenta que los analizadores de expresiones regulares vienen en algunas variedades. Básicamente, cada idioma implementa su propio analizador. Sin embargo, el analizador de expresiones regulares de Perl es el estándar de oro. Si tiene una opción, use Expresiones regulares compatibles con Perl.

Como se ve la expresión regular

La forma tradicional de escribir una expresión regular es rodeándola con barras.

/^he[l]{2}owworld$/

Así es como están escritos en Perl y JavaScript, y en muchas herramientas de línea de comandos como Less.

Sin embargo, muchos lenguajes más modernos (por ejemplo, Python) han optado por no incluir un tipo de expresión regular nativo, por lo que las expresiones regulares simplemente se escriben como cadenas:

r"^he[l]{2}owworld$"

Caracteres comunes de expresiones regulares

. Coincide con cualquier carácter (excepto las nuevas líneas, normalmente)
Escapa de un carácter especial (p. Ej. . coincide con un punto literal)
? El carácter anterior puede estar presente o no (p. Ej. /hell?o/ coincidiría hello o helo)
* Se permite cualquier número del carácter anterior (p. Ej. .* coincidirá con cualquier cadena de una sola línea, incluida una cadena vacía, y se usa mucho)
+ Uno o más de los caracteres anteriores (.+ es lo mismo que .* excepto que no coincidirá con una cadena vacía)
| «O», coincide con la sección anterior o la siguiente (p. Ej. hello|mad coincidirá con «hola» o «loco»)
() agrupe una sección. Esto puede ser útil para condicionales ((a|b)), multiplicadores ((hello)+), o para crear grupos para sustituciones (ver más abajo)
{} Especifique cuántos del carácter anterior (p. Ej. a{12} coincide con 12 «a» seguidas)
[] Coincide con cualquier personaje de este conjunto. - define rangos (p. ej. [a-z] es cualquier letra minúscula), ^ significa «no» (p. ej. [^,]+ coincidir con cualquier número de no comas seguidas)
^ Principio de línea
$ Fin de la línea

Atajos de caracteres en expresiones regulares

En la mayoría de las implementaciones de expresiones regulares, puede usar una barra invertida seguida de una letra (x) como atajo para un juego de caracteres. Aquí hay una lista de algunos comunes de Hoja de trucos de expresiones regulares de rexegg.com.

Regex en condicionales

El caso de uso más simple para las expresiones regulares en la programación es una comparación de cadenas. Esto se ve diferente en diferentes idiomas, por ejemplo:

// Perl
if ( "hello world" =~ /^he[l]{2}osworld$/ ) {..}
// JavaScript
if( /^he[l]{2}osworld$/.test("hello world") ) {..}
# Python
import re
if re.match(r"^he[l]{2}osworld$", "hello world"): ..

Regex en sustituciones

También puede utilizar expresiones regulares para manipular cadenas mediante sustitución. En los siguientes ejemplos, se imprimirá «mundo loco»:

// Perl
$hw = "hello world"; $hw =~ s/^(he[l]{2}o)s(world)$/mad 2/; print($hw)
// JavaScript
console.log("hello world".replace(/^(he[l]{2}o)s(world)$/, "mad $2"))
# Python
import re
print(re.replace(r"^(he[l]{2}o)s(world)$", r"mad 2", "hello world"))

Modificadores de expresiones regulares

Puede modificar el comportamiento de las expresiones regulares en función de algunos modificadores. Solo voy a ilustrar uno aquí, que es el modificador para que las expresiones regulares no distingan entre mayúsculas y minúsculas. En Perl, JavaScript y otros contextos de expresiones regulares más tradicionales, los modificadores se agregan después del último /. Los lenguajes más modernos suelen utilizar constantes en su lugar:

// Perl
if ( "HeLlO wOrLd" =~ /^he[l]{2}osworld$/i ) {..}
// JavaScript
if( /^he[l]{2}osworld$/i.test("HeLlO wOrLd") ) {..}
# Python
import re
if re.match(r"^he[l]{2}osworld$", "HeLlO wOrLd", flags=re.IGNORECASE): ..

Lookahead y lookbehind en expresiones regulares

Estos solo son compatibles con algunas implementaciones de expresiones regulares y le brindan la oportunidad de hacer coincidir cadenas que preceden o siguen a otras cadenas, pero sin incluir el prefijo o sufijo en la coincidencia en sí:

(Nuevamente, tomado de Hoja de trucos de expresiones regulares de rexegg.com)

Recursos de expresiones regulares

Eso es todo lo que tengo por ahora. Si deseas obtener más información, existen muchos recursos útiles:

  • Rexegg.com – Muchos artículos excelentes sobre la mayoría de los aspectos de las expresiones regulares
  • Regex101 – Un probador para su expresión regular, que ofrece algunas implementaciones diferentes
  • iHateRegex – Una colección de patrones de expresiones regulares de ejemplo para hacer coincidir algunos tipos comunes de cadenas (por ejemplo, número de teléfono, dirección de correo electrónico)
  • El oficial Documentación de expresiones regulares compatibles con Perl

Leave a Comment

You may also like