2016-05-30 1 views
4

Quand j'ai une chaîne comme ceci:Comment supprimer tout le texte entre les parenthèses externes dans une chaîne?

s1 = 'stuff(remove_me)' 

je peux facilement supprimer les parenthèses et le texte dans l'aide

# returns 'stuff' 
res1 = re.sub(r'\([^)]*\)', '', s1) 

comme expliqué here.

Mais je rencontre parfois des expressions imbriquées comme ceci:

s2 = 'stuff(remove(me))' 

Quand je lance la commande d'en haut, je me retrouve avec

'stuff)' 

J'ai aussi essayé:

re.sub('\(.*?\)', '', s2) 

ce qui me donne le même résultat.

Comment puis-je supprimer tout ce qui se trouve dans les parenthèses externes - y compris les parenthèses elles-mêmes - pour que je finisse avec 'stuff' (ce qui devrait fonctionner pour des expressions arbitrairement complexes)?

+0

Check [* supprimer le texte entre() et \ [\] en python *] (http: //stackoverflow.com/a/14598135/3832970). –

+0

@ WiktorStribiżew: Merci! Mais il s'agit d'expressions qui ne sont pas imbriquées. Et je suis à peu près certain qu'il existe quelque chose qui n'exige pas beaucoup de clauses if-else et une boucle for-loop. – Cleb

+1

Cette [réponse] (http://stackoverflow.com/a/12280660/3832970) contient la regex dont vous avez besoin mais vous avez besoin d'un module PyPi regex. –

Répondre

2

re matchs sont impatients de sorte qu'ils tentent de faire correspondre autant de texte que possible, pour le simple cas de test, vous mentionner laissez simplement la course regex:

>>> re.sub(r'\(.*\)', '', 'stuff(remove(me))') 
'stuff' 
+0

Oh, c'était simple ... Merci! – Cleb

+3

@Cleb être averti que cela ne vérifie pas si les accolades sont appariés. Par exemple. dans 'foo (bar) baz (spam) e) ggs', il ne restera que' fooggs'. –

+0

@ivan_pozdeev: Merci pour l'avertissement, bon à savoir! Dans mes exemples, ils devraient être jumelés, mais je vais quand même ajouter un chèque. – Cleb

1

Si vous êtes sûr que les parenthèses sont d'abord équilibrée, il suffit d'utiliser la gourmande Version:

re.sub(r'\(.*\)', '', s2) 
+0

Merci, même chose que la réponse de @ alexamici, mais mérite toujours un upvote. Si simple ... – Cleb

0

https://regex101.com/r/kQ2jS3/1

'(\(.*\))' 

Ceci capture les parenthèses furthest, et tout entre les parenthèses.

Votre ancienne regex capture les premières parenthèses, et tout entre les parenthèses next.

+0

Même chose que les deux autres réponses mais merci quand même (upvoted) ... :) – Cleb

2

Comme mentionné précédemment, vous auriez besoin d'un recursive regex pour faire correspondre les niveaux d'imbrication arbitraires, mais si vous savez qu'il ne peut y avoir un maximum d'un niveau d'imbrication un essai avec ce modèle:

\((?:[^)(]|\([^)(]*\))*\) 
  • [^)(] correspond à un caractère, ce n'est pas une parenthèse (negated class).
  • |\([^)(]*\) ou elle correspond à une autre paire () avec toute quantité de non)( intérieur.
  • (?: ...)* tout cela toute quantité de fois à l'intérieur ()

Here is a demo at regex101

Avant l'alternance utilisé [^)(] sans + quantificateurs à l'échec plus rapide si déséquilibrée.
Vous devez ajouter plus de niveaux d'imbrication possibles. Par exemple, pour un maximum de 2 niveaux:

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

Another demo at regex101

+0

Très sympa, merci pour l'explication détaillée (upvoted)! – Cleb

5

NOTE: \(.*\) correspond à la première ( de la gauche, correspond alors tout 0+ caractères (autre qu'un saut de ligne si un modificateur de DOTALL n'est pas activé) jusqu'au dernier), et ne tient pas compte des parenthèses imbriquées correctement.

Pour supprimer des parenthèses imbriquées correctement avec une expression régulière en Python, vous pouvez utiliser un \([^()]*\) simple (correspondant à un (, puis 0+ autres que les caractères ( et ) puis un )) dans un tout bloc à l'aide re.subn:

def remove_text_between_parens(text): 
    n = 1 # run at least once 
    while n: 
     text, n = re.subn(r'\([^()]*\)', '', text) # remove non-nested/flat balanced parts 
    return text 

Bascially: retirer le (...) sans ( et ) à l'intérieur jusqu'à ce qu'il n'y correspondance est trouvée. Utilisation:

print(remove_text_between_parens('stuff (inside (nested) brackets) (and (some(are)) here) here')) 
# => stuff here 

Une façon non-regex est également possible:

def removeNestedParentheses(s): 
    ret = '' 
    skip = 0 
    for i in s: 
     if i == '(': 
      skip += 1 
     elif i == ')'and skip > 0: 
      skip -= 1 
     elif skip == 0: 
      ret += i 
    return ret 

x = removeNestedParentheses('stuff (inside (nested) brackets) (and (some(are)) here) here') 
print(x)    
# => 'stuff here' 

Voir another Python demo

+0

Des exemples très instructifs, merci (upvoted)! – Cleb