2011-10-26 13 views
26

Estoy tratando de crear una expresión RegEx de .NET que equilibre correctamente mi paréntesis. Tengo la siguiente expresión RegEx:Uso de RegEx para equilibrar el paréntesis de coincidencia

func([a-zA-Z_][a-zA-Z0-9_]*)\(.*\) 

La cadena que estoy tratando de igualar es la siguiente:

"test -> funcPow((3),2) * (9+1)" 

Lo que debería suceder es expresión regular debe coincidir con todo, desde funcPow hasta el segundo paréntesis de cierre. Debería detenerse después del segundo paréntesis de cierre. En cambio, está haciendo coincidir todo el camino hasta el último paréntesis de cierre. RegEx está volviendo esto:

"funcPow((3),2) * (9+1)" 

debe devolver esto:

"funcPow((3),2)" 

Cualquier ayuda en esto sería apreciada.

Respuesta

36

expresiones regulares puede hacer definitivamente paréntesis equilibrado que empareja. Puede ser complicado y requiere un par de funciones Regex más avanzadas, pero no es demasiado difícil.

Ejemplo:

var r = new Regex(@" 
    func([a-zA-Z_][a-zA-Z0-9_]*) # The func name 

    \(      # First '(' 
     (?:     
     [^()]    # Match all non-braces 
     | 
     (?<open> \()  # Match '(', and capture into 'open' 
     | 
     (?<-open> \))  # Match ')', and delete the 'open' capture 
     )+ 
     (?(open)(?!))  # Fails if 'open' stack isn't empty! 

    \)      # Last ')' 
", RegexOptions.IgnorePatternWhitespace); 

se encontraron grupos equilibrados tiene un par de características, pero para este ejemplo, que sólo está utilizando la captura función de borrar. La línea (?<-open> \)) coincidirá con ) y eliminará la captura anterior "abierta".

La línea más complicada es (?(open)(?!)), así que déjame explicarte. (?(open) es una expresión condicional que solo coincide si hay una captura "abierta". (?!) es una expresión negativa que siempre falla. Por lo tanto, (?(open)(?!)) dice "si hay una captura abierta, entonces falla".

Microsoft's documentation fue muy útil también.

+0

Cambié la línea '[^()] * # Coincidir todos los no-llaves 'por lo que coincide() con nada dentro de –

+0

tenga en cuenta el' * '. Esto funciona genial gracias! –

-1

Las expresiones regulares solo funcionan en Regular Languages. Esto significa que una expresión regular puede encontrar cosas por el estilo "cualquier combinación de A y B". (ab o babbabaaa etc) pero que no puede encontrar "n una de, una b, n A". (a^n b a^n) Las expresiones regulares no pueden garantizar que el primer conjunto de a coincida con el segundo conjunto de a.

Debido a esto, no pueden coincidir con el mismo número de paréntesis de apertura y cierre. Sería bastante fácil escribir una función que atraviese la cadena un carácter a la vez. Tener dos contadores, uno para abrir paren, uno para cerrar. incremente los punteros a medida que recorre la cadena, si opening_paren_count != closing_parent_count devuelve falso.

+6

Eso es posible, pero ** regexes ** se puede usar en casi cualquier tipo de texto siempre que comprenda sus limitaciones. Los patrones recursivos/equilibrados son desagradables y (IMO) rara vez vale la pena el esfuerzo, pero * son * compatibles con muchos sabores de expresiones regulares. –

-1
func[a-zA-Z0-9_]*\((([^()])|(\([^()]*\)))*\) 

Puede usar eso, pero si está trabajando con .NET, puede haber mejores alternativas.

Esta parte ya saben:

func[a-zA-Z0-9_]*\(--weird part-- \) 

La parte parcialmente: --weird sólo significa; ( permite que cualquier carácter ., o | cualquier sección (.*) exista tantas veces como quiera )*. El único problema es que no puede hacer coincidir ningún carácter ., debe usar [^()] para excluir el paréntesis.

(([^()])|(\([^()]*\)))* 
+0

Debe especificar que esto funcionará con un solo nivel de anidación. –

+0

@ScottRippey: Aún funciona si hay una función dentro de esa función. El | condición maneja eso. ¿Puedes dar un ejemplo en el que esta expresión regular proporcione una coincidencia falsa? – rkw

+1

Funciona correctamente, y hace exactamente lo que OP pidió, por lo que es una buena respuesta. Sin embargo, está codificado para que solo coincida con un nivel de anidamiento, por lo que no podría coincidir: 'func (a (b (c) d) e)'. No está claro si el OP necesitó esto. –

18

El uso de grupos equilibrados, es:

Regex rx = new Regex(@"func([a-zA-Z_][a-zA-Z0-9_]*)\(((?<BR>\()|(?<-BR>\))|[^()]*)+\)"); 

var match = rx.Match("funcPow((3),2) * (9+1)"); 

var str = match.Value; // funcPow((3),2) 

(?<BR>\()|(?<-BR>\)) son un Balancing Group (la BR I utiliza para el nombre es para Brackets). Es más claro de esta manera (?<BR> \ ()|(?<-BR> \) ) tal vez, de modo que el \( y \) son más "evidente".

Si realmente odias a ti mismo (y el mundo/sus compañeros de programadores) lo suficiente como para usar estas cosas, se sugiere emplear la "pizca" espacio en blanco RegexOptions.IgnorePatternWhitespace y en todas partes :-)

+0

Creo que le falta la última parte crítica, '(? (BR) (?!))' –

+0

@ScottRippey No. Hay otras expresiones después del cierre ')'. La pregunta OP fue MUY precisa. Quiere 'funcsomething()', no analizar la expresión completa. Entonces, el primer soporte "desequilibrado" que encuentro es el corchete de cierre de mi sub-expresión. 'funcPow ((3), 2) * (9 + 1) -> funcPow ((3), 2)' – xanatos

+1

Oh, me di cuenta de que '(? (BR) (?!))' es solo para asegurar la apertura corsé tiene un corsé de cierre. Sitio web de Microsoft: "La subexpresión final (? (Open) (?!)), indica si las construcciones de anidación en la cadena de entrada están balanceadas correctamente" –

Cuestiones relacionadas