Utiliser RegEx pour équilibrer les parenthèses

J’essaie de créer une expression .NET RegEx qui équilibrera correctement mes parenthèses. J’ai l’expression RegEx suivante:

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

La chaîne que je cherche à faire correspondre est la suivante:

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

Ce qui devrait arriver, c’est que Regex devrait correspondre à tout, de funcPow à la deuxième parenthèse fermante. Il devrait s’arrêter après la deuxième parenthèse fermante. Au lieu de cela, il correspond jusqu’à la toute dernière parenthèse fermante. RegEx renvoie ceci:

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

Il devrait retourner ceci:

 "funcPow((3),2)" 

Toute aide à ce sujet serait appréciée.

Les expressions régulières peuvent certainement faire une correspondance équilibrée entre parenthèses. Cela peut être compliqué et nécessite quelques fonctionnalités Regex plus avancées, mais ce n’est pas trop difficile.

Exemple:

 var r = new Regex(@" func([a-zA-Z_][a-zA-Z0-9_]*) # The func name \( # First '(' (?: [^()] # Match all non-braces | (? \( ) # Match '(', and capture into 'open' | (?<-open> \) ) # Match ')', and delete the 'open' capture )+ (?(open)(?!)) # Fails if 'open' stack isn't empty! \) # Last ')' ", RegexOptions.IgnorePatternWhitespace); 

Les groupes de correspondance équilibrés ont plusieurs fonctionnalités, mais pour cet exemple, nous utilisons uniquement la fonctionnalité de suppression de capture. La ligne (?<-open> \) ) correspondra à a ) et supprimera la capture “ouverte” précédente.

La ligne la plus délicate est (?(open)(?!)) , alors laissez-moi l’expliquer. (?(open) est une expression conditionnelle qui correspond uniquement s’il existe une capture “ouverte”. (?!) est une expression négative qui échoue toujours. Par conséquent, (?(open)(?!)) dit “s’il y a une capture ouverte, puis échouer “.

La documentation de Microsoft était également très utile.

En utilisant des groupes équilibrés, c’est:

 Regex rx = new Regex(@"func([a-zA-Z_][a-zA-Z0-9_]*)\(((?
\()|(?<-BR>\))|[^()]*)+\)"); var match = rx.Match("funcPow((3),2) * (9+1)"); var str = match.Value; // funcPow((3),2)

(?
\()|(?<-BR>\))
sont un groupe d’équilibrage (le BR j’ai utilisé pour le nom est pour des Brackets ). C’est plus clair de cette façon (?
\ ( )|(?<-BR> \) ) peut-être, pour que les \( et \) soient plus “évidents”.

Si vous vous détestez vraiment (et le monde / vos collègues co-programmeurs) assez pour utiliser ces choses, je suggère d’utiliser le RegexOptions.IgnorePatternWhitespace et “saupoudrer” un espace blanc partout 🙂

Les expressions régulières ne fonctionnent que sur les langues normales . Cela signifie qu’une expression régulière peut trouver des choses du type “toute combinaison de a et de b” ( ab ou babbabaaa etc.), mais ne peut pas trouver les ” n a, un b, n a”. (A a^nba^n ) Les expressions régulières ne peuvent pas garantir que le premier ensemble de a corresponde au deuxième ensemble de a.

Pour cette raison, ils ne peuvent pas faire correspondre le même nombre de parenthèses ouvrantes et fermantes. Il serait assez facile d’écrire une fonction qui traverse la chaîne, un caractère à la fois. Avoir deux compteurs, un pour l’ouverture paren, un pour la fermeture. incrémente les pointeurs au fur et à mesure que vous traversez la chaîne, si opening_paren_count != closing_parent_count renvoie false.

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

Vous pouvez l’utiliser, mais si vous travaillez avec .NET, il peut y avoir de meilleures alternatives.

Vous connaissez déjà cette partie:

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

La partie bizarre signifie simplement; ( autorisez n’importe quel caractère ou toute section (.*) à exister autant de fois qu’il le souhaite )* . Le seul problème est que vous ne pouvez faire correspondre aucun personnage . , vous devez utiliser [^()] pour exclure la parenthèse.

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