Aprendizaje de expresiones regulares [cerrado]

166

Realmente no entiendo las expresiones regulares. ¿Me los puede explicar de una manera fácil de seguir? Si hay herramientas o libros en línea, ¿podría también vincularlos?

Teifion
fuente

Respuestas:

789

La parte más importante son los conceptos. Una vez que comprenda cómo funcionan los bloques de construcción, las diferencias en la sintaxis equivalen a poco más que dialectos suaves. Una capa en la parte superior de la sintaxis de su motor de expresión regular es la sintaxis del lenguaje de programación que está utilizando. Los lenguajes como Perl eliminan la mayor parte de esta complicación, pero tendrá que tener en cuenta otras consideraciones si está utilizando expresiones regulares en un programa en C.

Si piensa en las expresiones regulares como bloques de construcción que puede mezclar y combinar a su gusto, le ayuda a aprender a escribir y depurar sus propios patrones, pero también a entender los patrones escritos por otros.

Comience simple

Conceptualmente, las expresiones regulares más simples son caracteres literales. El patrón Ncoincide con el carácter 'N'.

Las expresiones regulares una al lado de la otra coinciden con las secuencias. Por ejemplo, el patrón Nickcoincide con la secuencia 'N' seguida de 'i' seguida de 'c' seguida de 'k'.

Si alguna vez usó grepen Unix, aunque solo sea para buscar cadenas de aspecto ordinario, ¡ya ha estado usando expresiones regulares! (El rein se greprefiere a expresiones regulares).

Ordenar desde el menú

Agregando un poco de complejidad, puede hacer coincidir 'Nick' o 'nick' con el patrón [Nn]ick. La parte entre corchetes es una clase de caracteres , lo que significa que coincide exactamente con uno de los caracteres incluidos. También puede usar rangos en las clases de caracteres, por lo que [a-c]coincide con 'a' o 'b' o 'c'.

El patrón .es especial: en lugar de hacer coincidir solo un punto literal, coincide con cualquier carácter . Es lo mismo conceptualmente que la clase de personaje realmente grande [-.?+%$A-Za-z0-9...].

Piense en las clases de personajes como menús: elija solo uno.

Atajos útiles

El uso .puede ahorrarle mucho tipeo, y hay otros accesos directos para patrones comunes. Digamos que quieres hacer coincidir un dígito: una forma de escribir eso es [0-9]. Los dígitos son un objetivo de coincidencia frecuente, por lo que podría utilizar el acceso directo \d. Otros son \s(espacios en blanco) y \w(caracteres de palabras: alfanuméricos o guiones bajos).

Las variantes en mayúsculas son sus complementos, por lo que \Scoincide con cualquier carácter que no sea un espacio en blanco, por ejemplo.

Una vez no es suficiente

A partir de ahí, puede repetir partes de su patrón con cuantificadores . Por ejemplo, el patrón ab?ccoincide con 'abc' o 'ac' porque el ?cuantificador hace que el subpatrón que modifica sea opcional. Otros cuantificadores son

  • * (cero o más veces)
  • + (una o más veces)
  • {n}(exactamente n veces)
  • {n,}(al menos n veces)
  • {n,m}(al menos n veces pero no más de m veces)

Al unir algunos de estos bloques, el patrón [Nn]*ickcoincide con todos

  • ick
  • Mella
  • mella
  • Nnick
  • nNick
  • nnick
  • (y así)

El primer partido demuestra una lección importante: ¡ *siempre tiene éxito! Cualquier patrón puede coincidir con cero veces.

Algunos otros ejemplos útiles:

  • [0-9]+(y su equivalente \d+) coincide con cualquier número entero no negativo
  • \d{4}-\d{2}-\d{2} coincide con fechas formateadas como 2019-01-01

Agrupamiento

Un cuantificador modifica el patrón a su izquierda inmediata. Puede esperar 0abc+0que coincida con '0abc0', '0abcabc0', etc., pero el patrón inmediatamente a la izquierda del cuantificador más es c. Esto significa 0abc+0coincide con '0abc0', '0abcc0', '0abccc0', y así sucesivamente.

Para unir una o más secuencias de 'abc' con ceros en los extremos, use 0(abc)+0. Los paréntesis denotan un subpatrón que se puede cuantificar como una unidad. También es común que los motores de expresión regular guarden o "capturen" la parte del texto de entrada que coincide con un grupo entre paréntesis. Extraer bits de esta manera es mucho más flexible y menos propenso a errores que contar índices y substr.

Alternancia

Anteriormente, vimos una forma de hacer coincidir 'Nick' o 'nick'. Otro es con alternancia como en Nick|nick. Recuerde que la alternancia incluye todo a su izquierda y todo a su derecha. Utilizar agrupación paréntesis, a limitar el alcance de |, por ejemplo , (Nick|nick).

Para otro ejemplo, podría escribir equivalentemente [a-c]como a|b|c, pero es probable que esto sea subóptimo porque muchas implementaciones suponen que las alternativas tendrán longitudes mayores que 1.

Escapar

Aunque algunos personajes coinciden, otros tienen significados especiales. El patrón \d+no coincide con la barra invertida seguida de una D minúscula seguida de un signo más: para obtener eso, usaríamos \\d\+. Una barra invertida elimina el significado especial del siguiente carácter.

Codicia

Los cuantificadores de expresiones regulares son codiciosos. Esto significa que coinciden con la mayor cantidad de texto posible y permiten que todo el patrón coincida con éxito.

Por ejemplo, digamos que la entrada es

"Hola", dijo ella, "¿Cómo estás?"

Puede esperar ".+"que solo coincida con 'Hola', y luego se sorprenderá cuando vea que coincide con 'Hola' a través de '¿usted?'.

Para cambiar de codicioso a lo que podría considerar cauteloso, agregue un extra ?al cuantificador. Ahora comprende cómo funciona \((.+?)\)el ejemplo de su pregunta. Coincide con la secuencia de un paréntesis izquierdo literal, seguido de uno o más caracteres, y termina con un paréntesis derecho.

Si su entrada es '(123) (456)', la primera captura será '123'. Los cuantificadores no codiciosos desean permitir que el resto del patrón comience a coincidir lo antes posible.

(En cuanto a su confusión, no conozco ningún dialecto de expresión regular en el ((.+?))que haga lo mismo. Sospecho que algo se perdió en la transmisión en algún momento).

Anclas

Use el patrón especial ^para hacer coincidir solo al comienzo de su entrada y $para hacer coincidir solo al final. Hacer "sujetalibros" con tus patrones donde dices: "Sé lo que hay al frente y atrás, pero dame todo entre" es una técnica útil.

Digamos que quieres hacer coincidir los comentarios del formulario

-- This is a comment --

que iba a escribir ^--\s+(.+)\s+--$.

Construye tu propio

Las expresiones regulares son recursivas, por lo que ahora que comprende estas reglas básicas, puede combinarlas como desee.

Herramientas para escribir y depurar expresiones regulares:

Libros

Recursos gratuitos

Nota

†: La afirmación anterior que .coincide con cualquier personaje es una simplificación para fines pedagógicos que no es estrictamente cierta. El punto coincide con cualquier carácter, excepto la nueva línea, "\n"pero en la práctica rara vez se espera que un patrón .+cruce una línea nueva. Las expresiones regulares de Perl tienen un /sinterruptor y Java Pattern.DOTALL, por ejemplo, para hacer .coincidir cualquier carácter. Para los idiomas que no tienen esa función, puede usar algo como [\s\S]"cualquier espacio en blanco o cualquier espacio en blanco", en otras palabras, cualquier cosa.

Greg Bacon
fuente
14
También puede usar el método de prueba y error, y seguir el probador y depurador de expresiones
regulares en
2
Vale la pena mencionar que, a pesar de ser un patrón similar, a{,m}no es una cosa, al menos en Javascript, Perl y Python.
Financia la demanda de Mónica el
2
Vale la pena mencionar que hay diferentes tipos de motores de expresión regular, todos con diferentes conjuntos de características y reglas sintácticas.
hek2mgl
1
hackr.io/tutorials/learn-regular-expressions-regex es un gran lugar para encontrar los mejores tutoriales de expresiones regulares en línea. Todos los tutoriales aquí son enviados y recomendados (votados como SO) por la comunidad de programación.
Saurabh Hooda
2
Aprecio sus esfuerzos para traer todo aquí en pocas palabras.
Saurabh Tiwari