Coincidencia de expresión regular

Quiero escribir una expresión regular que coincida con cualquier cosa entre

() (()) (()()) ((())) ()()() 

etc.

Todas estas respuestas que afirman que no se pueden usar patrones para hacer coincidir una cadena con parens nesteds equilibrados son completamente incorrectas. No es práctico pretender que los patrones que coinciden con los lenguajes de progtwigción modernos están restringidos a los “lenguajes regulares” en el sentido patológico de los libros de texto. Tan pronto como permita las referencias, no lo son. Esto permite que los patrones del mundo real coincidan mucho más que las versiones de los libros de texto, haciéndolos mucho más prácticos.

El patrón más simple para emparejar parens balanceados es \((?:[^()]*+|(?0))*\) . Pero nunca debes escribir eso , porque es demasiado compacto para ser leído fácilmente. Siempre debe escribirlo con el modo /x para permitir el espacio en blanco y los comentarios. Así que escríbelo así:

 m{ \( # literal open paren (?: # begin alternation group [^()]*+ # match nonparens possessively | # or else (?0) # recursively match entire pattern )* # repeat alternation group \) # literal close paren }x 

También hay mucho que decir para nombrar tus abstracciones y desacoplar su definición y su orden de su ejecución. Eso lleva a este tipo de cosas:

 my $nested_paren_rx = qr{ (?&nested_parens) (?(DEFINE) (? \( ) (? \) ) (? [^()] ) (? (?&open) (?: (?&nonparens) *+ | (?&nested_parens) ) * (?&close) ) ) }x; 

La segunda forma ahora puede incluirse en patrones más grandes.

Nunca dejes que nadie te diga que no puedes usar un patrón para que coincida con algo que se define recursivamente. Como acabo de demostrar, ciertamente puedes.

Mientras lo hace, asegúrese de nunca escribir patrones de ruido de línea. No es necesario, y no deberías. No se puede mantener un lenguaje de progtwigción que prohíba espacios en blanco, comentarios, subrutinas o identificadores alfanuméricos. Entonces usa todas esas cosas en tus patrones.

Por supuesto, ayuda a elegir el idioma correcto para este tipo de trabajo. ☺

En caso de que esté atascado con un lenguaje cuya syntax de expresión regular no sea compatible con la coincidencia recursiva, le doy mi sencilla implementación de Javascript desde la cual podrá hacer la suya en el idioma que elija:

 function testBraces(s) { for (var i=0, j=0; i=0; i++) switch(s.charAt(i)) { case '(': { j++ ; break; } case ')': { j-- ; break; } } return j == 0; } 

Y aquí puedes jugar con él: http://jsfiddle.net/BFsn2/

Tal estructura anidada no puede ser manejada de manera efectiva por expresiones regulares. Lo que necesitas es una gramática y un analizador sintáctico para esa gramática. En tu caso, la gramática es bastante simple. Si está usando python intente pyparsing o funcparserlib.

Con pyparsing puedes hacer lo siguiente:

 from pyparsing import nestedExpr nestedExpr().parseString( "(some (string you) (want) (to) test)" ).asList() 

Esto devolverá una lista que contiene los componentes analizados de la cadena anidada. El delimitador predeterminado para nestedExpr es paréntesis, por lo que no tiene que hacer nada extra. Si quieres usar funcpasrerlib, puedes probar lo siguiente

 from funcparserlib.parser import forward_decl, many, a bracketed = forward_decl() bracketed.define(a('(') + many(bracketed) + a(')')) 

Después de esto puedes llamar

 bracketed.parse( "( (some) ((test) (string) (you) (want)) (to test))" ) 

y devolverá los elementos analizados en una tupla.

Les deseo buena suerte. Necesitarías un autómata de estado finito con una stack para analizar algo como esto. No se puede analizar utilizando solo expresiones regulares, ya que no es lo suficientemente potente.