2009-12-23 8 views
6

J'essaie de supprimer le texte entre parenthèses (avec les parenthèses elles-mêmes) mais j'ai des problèmes avec le scénario où il y a des parenthèses entre parenthèses. C'est la méthode que je utilise (Ruby):Retrait du texte entre parenthèses (parenthèses entre parenthèses prob)

sentence.gsub(/\(.*?\)/, "") 

et qui fonctionne bien jusqu'à ce que j'ai une phrase telle que:

"This is (a test (string))" 

Ensuite, les bobines d'arrêt ci-dessus. Quelqu'un at-il une idée de comment faire cela? Je suis complètement perplexe.

+1

s'il y a un nombre inégal de balises d'ouverture et de fermeture comme dans '(foo) bar) 'ou s'il n'y a pas de paires comme dans' foo) (bar'? – Gumbo

+0

Je n'ai pas besoin de rendre compte de ce scenerio – TenJack

Répondre

10

Un approch est de remplacer les groupes parenthétiques de l'intérieur:

x = string.dup 
while x.gsub!(/\([^()]*\)/,""); end 
x 
10

On dirait que vous avez besoin d'être gourmand, en enlevant le ?

>> "This is (a test (string))".gsub(/\(.*\)/, "") 
=> "This is " 

Cela fait aller au dernier ) au lieu de la première. Cependant, il ne capture pas l'imbrication, car une regex ne peut pas le faire.

+1

Ne fait pas ce qu'il devrait pour 'c'est (entre (parenthèses)) et (ainsi est-ce) text';) – Juliet

+1

L'échappement des parenthèses n'a jamais fait partie du problème; le PO l'a fait, mais les barres obliques inverses ne sont pas apparues parce qu'il n'a pas appliqué le bon formatage du code source. –

0

La réponse de jleedev fonctionnera s'il n'y a qu'un seul ensemble de parenthèses au niveau le plus externe; dans ce cas, rendre l'expression des entrailles de ces parenthèses gourmande devrait faire l'affaire.

Cependant, et peut-être un peu surprenant, regExps tel que défini dans Perl, Java, Ruby et quelques autres langues, mais aussi grep et sed ne conviennent pas à faire face à ce problème. Il n'y a pas d'expression rationnelle pour traiter le cas général des délimiteurs imbriqués. C'est une des raisons pour lesquelles les gens de SO vous crient quand vous voulez utiliser une expression rationnelle pour traiter du HTML ou du XML. Il est intéressant de noter que le créateur du langage Lua a résolu ce problème en ajoutant un nouveau motif correspondant au langage de motif par ailleurs plutôt simple. Regardez la poignée inférieure des lignes dans http://www.lua.org/pil/20.2.html!

+1

Les modèles récursifs de Perl peuvent gérer les délimiteurs imbriqués. – newacct

+0

Oups! Fixe, merci. –

1

Le Perl regex suivant va matcher entre parenthèses équilibrées:

/(\((?:[^\(\)]++|(?1))*\))/ 

Cependant, au moment où vous arrivez à ce point, vous n'êtes pas techniquement en utilisant des expressions « réguliers » plus.

+3

Plus précisément, vous n'utilisez plus Ruby non plus. –

+0

c'est magnifique! Après avoir joué avec, j'ai trouvé sa version Ruby (1.9/Oniguruma):/(? \ ((?: [^ \ (\)] ++ | \ g ) * \)) / –

2

Le problème est que les langues contenant des parenthèses imbriquées (ou bien quoi que ce soit imbriqué, quoi que ce soit OIEau qui nécessite la récursivité) ne sont pas réguliers, ils sont au moins sans contexte. Cela signifie qu'ils ne peuvent pas être décrits par une grammaire régulière. Les expressions régulières sont une notation compacte pour les grammaires régulières. Ergo, les parenthèses imbriquées ne peuvent pas être décrites par des expressions régulières.

Cependant, nous ne parlons pas d'expressions régulières ici, nous parlons de Regexp s. Alors que leur sémantique et leur syntaxe sont (très) vaguement basées sur des expressions régulières, elles sont assez différentes et surtout beaucoup plus puissantes. Selon la saveur particulière de Regexp que vous utilisez, ils peuvent ou non être en mesure d'exprimer la récursivité et donc d'analyser les parenthèses imbriquées. Perl Regex, par exemple peut parser des parenthèses imbriquées.Je ne suis pas sûr si le Regexp de Ruby peut, mais je m'en fous vraiment, parce que la façon dont Regexp est plus puissante que les expressions régulières est généralement accomplie en boulonnant de plus en plus de syntaxe sur eux.

Ceci transforme les expressions régulières, conçues pour être simples, en monstres incompréhensibles. (Si vous pouvez dire en un coup d'oeil ce que le Perl Regex posté par @Anon fait, alors allez-y, mais je ne peux pas et donc je préfère ne pas l'utiliser.)

Je préfère utiliser un analyseur plus puissant, plutôt que d'un complexe Regexp.

Dans ce cas, vous disposez d'un langage sans contexte, vous pouvez donc utiliser un analyseur de descente récursif très simple. Vous pouvez encore simplifier votre analyseur de descente récursif en traitant les sous-parties qui sont régulière avec une expression régulière. Enfin, si vous remplacez la récursion dans l'analyseur de descente récursive avec itération + mutation et faire une utilisation intelligente de la sémantique booléennes de Ruby, l'analyseur entier devient essentiellement condensé vers le bas pour cette seule ligne:

while str.gsub!(/\([^()]*?\)/, ''); end 

que je ne pense pas est trop mauvais.

est ici la chose entière avec un certain retrait supplémentaire de double espaces et (bien sûr) une suite de tests:

require 'test/unit' 
class TestParenthesesRemoval < Test::Unit::TestCase 
    def test_that_it_removes_even_deeply_nested_parentheses 
    str = 'This is (was?) some ((heavily) parenthesized (but not overly so 
      (I hope))) text with (superflous) parentheses:)(.' 
    res = 'This is some text with parentheses:)(.' 

    while str.gsub!(/\([^()]*?\)/, ''); end 
    str.squeeze!(' ') 

    assert_equal res, str 
    end 
end 
Questions connexes