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?
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.
Conceptualmente, las expresiones regulares más simples son caracteres literales. El patrón N
coincide con el carácter 'N'.
Las expresiones regulares una al lado de la otra coinciden con las secuencias. Por ejemplo, el patrón Nick
coincide con la secuencia 'N' seguida de 'i' seguida de 'c' seguida de 'k'.
Si alguna vez usó grep
en Unix, aunque solo sea para buscar cadenas de aspecto ordinario, ¡ya ha estado usando expresiones regulares! (El re
in se grep
refiere a expresiones regulares).
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.
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 \S
coincide con cualquier carácter que no sea un espacio en blanco, por ejemplo.
A partir de ahí, puede repetir partes de su patrón con cuantificadores . Por ejemplo, el patrón ab?c
coincide 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]*ick
coincide con todos
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-01Un cuantificador modifica el patrón a su izquierda inmediata. Puede esperar 0abc+0
que coincida con '0abc0', '0abcabc0', etc., pero el patrón inmediatamente a la izquierda del cuantificador más es c
. Esto significa 0abc+0
coincide 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
.
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.
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.
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).
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+--$
.
Las expresiones regulares son recursivas, por lo que ahora que comprende estas reglas básicas, puede combinarlas como desee.
†: 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 /s
interruptor 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.
a{,m}
no es una cosa, al menos en Javascript, Perl y Python.