2009-12-23 23 views
6

Ich versuche, Text in Klammern (zusammen mit den Klammern selbst) zu entfernen, habe jedoch Probleme mit dem Szenario, in dem Klammern in Klammern stehen. Dies ist die Methode, die ich (in Ruby) bin mit:Entfernen von Text in Klammern (Klammern in Klammern prob)

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

und das funktioniert gut, bis ich einen Satz haben, wie:

"This is (a test (string))" 

Dann werden die oben würgt. Hat jemand eine Idee, wie man das macht? Ich bin völlig ratlos.

+1

Was, wenn es eine ungleiche Anzahl von Öffnungs- und Schließ Tags wie in '(foo) bar) 'oder wenn es keine Paare wie in' foo gibt) (bar'? – Gumbo

+0

Ich muss diesen scenerio nicht berücksichtigen. – TenJack

Antwort

10

One approch ist es, die eingeklammerten Gruppen von innen zu ersetzen out: nicht sind

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

Sieht aus wie Sie gierig sein müssen, durch die ?

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

zu entfernen, die es an die letzte ) anstelle des ersten gehen macht. Es nimmt jedoch keine Verschachtelung auf, weil eine Regex das nicht kann.

+1

Tut nicht, was es für 'das ist (in (Klammern)) und (so ist das) text';) – Juliet

+1

Das Weglassen der Klammern war nie Teil des Problems; Das OP hat das gemacht, aber die umgekehrten Schrägstriche sind nicht aufgetaucht, weil er nicht die richtige Quellcode-Formatierung angewendet hat. –

0

Die Antwort von jleedev funktioniert, wenn nur ein Satz Klammern auf der äußersten Ebene steht; In diesem Fall sollte der Ausdruck für die Innereien dieser Klammern gierig sein.

Allerdings, und vielleicht ein wenig überraschend, Regexps definiert wie in Perl, Java, Ruby und einige anderen Sprachen, sondern auch grep und sed sind nicht geeignet, um mit diesem Problem fertig zu werden. Es gibt keine Regexp für den allgemeinen Fall verschachtelter Trennzeichen. Dies ist einer der Gründe, warum Leute auf SO Sie anschreien, wenn Sie einen regulären Ausdruck verwenden wollen, um HTML oder XML zu verarbeiten.

Interessanterweise hat der Ersteller der Lua-Sprache dieses Problem angegangen, indem er der ansonsten recht einfachen Mustersprache ein neues passendes Muster hinzugefügt hat. Schauen Sie sich die unteren paar Zeilen in http://www.lua.org/pil/20.2.html an!

+1

Perls rekursive Muster können verschachtelte Trennzeichen verarbeiten. – newacct

+0

Hoppla! Fest, danke. –

1

Die folgenden Perl regex wird ausgeglichen Klammern entsprechen:

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

jedoch durch die Zeit, die Sie zu diesem Punkt zu gelangen, sind Sie technisch nicht mehr „normale“ Ausdrücken.

+3

Genauer gesagt, Sie verwenden Ruby auch nicht mehr. –

+0

das ist schön! Nachdem ich damit herumgespielt habe, habe ich seine Version Ruby (1.9/Oniguruma) gefunden:/(? \ ((?: [^ \ (\)] ++ | \ g ) * \)) / –

2

Das Problem dabei ist, dass Sprachen verschachtelte Klammern (erfordert oder in der Tat etwas verschachtelt, IOW alles, was Rekursion) enthält, Regelmäßig sind sie zumindest kontextfrei. Dies bedeutet, dass sie nicht mit einer regulären Grammatik beschrieben werden können. Reguläre Ausdrücke sind eine kompakte Notation für reguläre Grammatiken. Ergo, verschachtelte Klammern können nicht durch reguläre Ausdrücke beschrieben werden.

Allerdings sprechen wir hier nicht über reguläre Ausdrücke, wir sprechen über Regexp s. Während ihre Semantik und Syntax (sehr) lose auf regulären Ausdrücken basieren, sind sie sehr unterschiedlich und besonders viel mächtiger. Abhängig von dem speziellen Geschmack von , den Sie verwenden, können oder können sie nicht in der Lage sein, Rekursion auszudrücken und somit verschachtelte Klammern zu parsen. Perl Regex, zum Beispiel kann verschachtelte Klammern analysieren.Ich bin mir nicht sicher, ob Rubys Regexp es kann, aber das ist mir egal, weil die Art und Weise, wie Regexp mächtiger als reguläre Ausdrücke sind, im Allgemeinen dadurch erreicht wird, dass immer mehr Syntax auf ihnen verschraubt wird.

Dies verwandelt reguläre Ausdrücke, die einfach zu sein sind, in unverständliche Monster. (Wenn Sie auf einen Blick erkennen können, was der Perl Regex von @Anon tut, dann gehen Sie dafür. Aber ich kann nicht und daher bevorzuge ich es nicht zu verwenden.)

Ich bevorzuge einen leistungsfähigeren Parser, eher als ein Komplex Regexp.

In diesem Fall haben Sie eine kontextfreie Sprache, daher können Sie einen sehr einfachen rekursiven Sink-Parser verwenden. Sie können Ihren rekursiven Descent-Parser weiter vereinfachen, indem Sie die Unterabschnitte regulär mit einem regulären Ausdruck behandeln. Schließlich, wenn Sie die Rekursion im Rekursiver Abstieg mit Iteration + Mutation ersetzen und geschickten Einsatz von Ruby boolean Semantik machen, wird der gesamte Parser grundsätzlich kondensiert bis zu dieser einzigen Zeile:

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

Was ich glaube nicht, ist schade.

Hier ist die ganze Sache mit einiger zusätzlichen Entfernung von doppelten Leerzeichen und (natürlich) eine Testsuite:

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 
Verwandte Themen