2010-04-06 6 views
3

j'ai besoin de tous les caractères entre « (» et «) » caractères.Trouver tous les caractères entre parenthèses avec un Regex .NET

var str = "dfgdgdfg (aaa.bbb) sfd (c) fdsdfg ( ,ddd (eee))"; 

Dans cet exemple, je dois obtenir 3 cordes:

(aaa.bbb) 
(c) 
( ,ddd (eee)) 

Quel modèle que je dois écrire? S'il vous plaît, aidez.

+5

Modèles imbriqués? C'est irrégulier. – kennytm

+0

OK. si str est "dfgdgdfg (aaa.bbb) sfd (c) fdsdfg" Qu'est-ce qu'un motif pour obtenir tous les caractères entre accolades? :) – Laritari

+0

@KennyTM: hehe, quand vont-ils jamais apprendre! – leppie

Répondre

4

Essayez quelque chose comme ceci:

\(([^)]+)\)

Edit: En fait, cela ne tout à fait travail pour le dernier bit - cette expression ne saisit pas la dernière sous-chaîne correctement. J'ai répondu à cette question afin que quelqu'un avec plus de temps puisse l'étoffer pour le faire fonctionner correctement.

+0

Merci. Ça aide. – Laritari

1

Vous avez besoin d'un combo lexer/analyseur, ou utilisez un lexeur avec le support de la pile. Mais regex en tant que tel, ne vous mènera nulle part.

+0

Merci. Je l'ai compris. – Laritari

1

Vous avez besoin d'une récursivité pour cela.

Un exemple Perl:

#!/usr/bin/perl 

$re = qr/
    (      # start capture buffer 1 
     \(     # match an opening paren 
     (   # capture buffer 2 
     (?:     # match one of: 
      (?>    #  don't backtrack over the inside of this group 
       [^()]+ #  one or more 
      )    #  end non backtracking group 
     |     #  ... or ... 
      (?1)   #  recurse to opening 1 and try it again 
     )*     # 0 or more times. 
     )   # end of buffer 2 
     \)     # match a closing paren 
    )      # end capture buffer one 
    /x; 


sub strip { 
my ($str) = @_; 
while ($str=~/$re/g) { 
    $match=$1; $striped=$2; 
    print "$match\n"; 
    strip($striped) if $striped=~/\(/; 
    return $striped; 
    } 
} 


$str="dfgdgdfg (aaa.bbb) sfd (c) fdsdfg ( ,ddd (eee))"; 

print "\n\nstart=$str\n"; 

while ($str=~/$re/g) { 
    strip($1) ; 
} 

Sortie:

start=dfgdgdfg (aaa.bbb) sfd (c) fdsdfg ( ,ddd (eee)) 
(aaa.bbb) 
(c) 
( ,ddd (eee)) 
(eee) 
0

Si vous avez seulement besoin de gérer un seul niveau de l'imbrication vous pouvez utiliser une paire de motifs mutuellement exclusifs. Ou vous pouvez ignorer les expressions régulières et simplement analyser la chaîne directement. Incrémente une variable d'état sur (, décrémente sur), et imprime une ligne quand elle revient à zéro.

0

Comme déjà mentionné par d'autres: regex ne convient pas pour une telle tâche. Cependant, si vos parenthèses ne dépassent pas un nombre fixe d'imbrications, vous pouvez le faire, mais si l'imbrication peut être de 3 ou plus, l'expression régulière deviendra difficile à écrire (et à maintenir!). Jetez un oeil à l'expression rationnelle qui correspond entre parenthèses avec au plus une parenthèse imbriquée dans ce:

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

qui signifie:

\(  # match the character '(' 
(?:  # start non-capture group 1 
    [^()] # match any character not from the set {'(', ')'} 
    |  # OR 
    \(  # match the character '(' 
    [^)]* # match any character not from the set {')'} and repeat it zero or more times 
    \)  # match the character ')' 
)*   # end non-capture group 1 and repeat it zero or more times 
\)   # match the character ')' 

La version pour 3 fera vos yeux saignent! Vous pourriez aller avec la fonctionnalité .NET de correspondance rationnelle récursive, mais personnellement, je n'irais pas: arroser la récursion à l'intérieur de la regex mène à la folie!(pas vraiment bien sûr, mais regex est assez difficile à comprendre et à mélanger récursion au mélange, ne rend pas plus clair IMO)

Je voudrais juste écrire une petite méthode qui pourrait ressembler à cet extrait de Python:

def find_parens(str): 

    matches = [] 
    parens = 0 
    start_index = -1 
    index = 0 

    for char in str: 
     if char == '(': 
      parens = parens+1 
      if start_index == -1: 
       start_index = index 
     if char == ')': 
      parens = parens-1 
      if parens == 0 and start_index > -1: 
       matches.append(str[start_index:index+1]) 
       start_index = -1 
     index = index+1 

    return matches 

for m in find_parens("dfgdgdfg (aaa.bbb) sfd (c) fdsdfg ( ,ddd (eee))"): 
    print(m) 

qui imprime:

(aaa.bbb) 
(c) 
( ,ddd (eee)) 

Je ne suis pas familier avec C#, mais le code Python ci-dessus lit comme code pseudo et ne prendrait pas beaucoup d'efforts pour convertir en C# Je présume.

1

ne dis pas que cela vaut mieux que Regex, mais voici une autre option

public static IEnumerable<string> InParen(string s) 
    { 
     int count = 0; 
     StringBuilder sb = new StringBuilder(); 
     foreach (char c in s) 
     { 
      switch (c) 
      { 
       case '(': 
        count++; 
        sb.Append(c); 
        break; 
       case ')': 
        count--; 
        sb.Append(c); 
        if (count == 0) 
        { 
         yield return sb.ToString(); 
         sb = new StringBuilder(); 
        } 
        break; 
       default: 
        if (count > 0) 
         sb.Append(c); 
        break; 
      } 
     } 
    } 
1

Vous voulez utiliser la fonction de groupe correspondant équilibré de .net expressions régulières.

var s = "dfgdgdfg (aaa.bbb) sfd (c) fdsdfg ( ,ddd (eee))"; 
var exp = "\([^()]*((?<paren>\()[^()]*|(?<close-paren>\))[^()]*)*(?(paren)(?!))\)"; 
var matches = Regex.Matches(s,exp); 
Questions connexes