2009-12-23 271 views
6

我想刪除括號內的文本(以及圓括號本身),但是在圓括號內有圓括號的場景中遇到問題。這是我使用(用Ruby)的方法:刪除圓括號內的文本(圓括號內的圓括號)

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

和正常工作,直到我有一個句子,如:

"This is (a test (string))" 

接着上面的扼流圈。任何人有任何想法如何做到這一點?我完全難倒了。

+1

如果什麼有不等數量的開始和結束標記的像'(富)條) '或者如果沒有像'foo)(bar')那樣的對嗎? – Gumbo 2009-12-23 05:39:30

+0

我不需要考慮這個scenerio。 – TenJack 2009-12-23 10:07:59

回答

10

一個計算策略是從內到外更換的括號組:

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

看起來你需要貪婪,通過移除?

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

這使得去到最後)而不是第一個。但它不捕獲嵌套,因爲正則表達式不能這樣做。

+1

對於'this(in(括號))和' )text';) – Juliet 2009-12-23 02:59:55

+1

轉義括號不是問題的一部分; OP做到了,但反斜槓沒有顯示出來,因爲他沒有使用適當的源代碼格式。 – 2009-12-23 04:12:12

0

如果最外層只有一組圓括號,jleedev的答案將會起作用;在這種情況下,讓那些括號內臟貪婪的表達方式應該是有用的。

然而,也許有點出人意料的是,正則表達式中的Perl,Java的,Ruby和其他一些語言的定義,但也grepsed不適合處理這一問題。處理嵌套分隔符的一般情況沒有任何正則表達式。這就是爲什麼當你想使用正則表達式來處理HTML或XML的時候,所有人都會對你大喊大叫。

有趣的是,Lua語言的創建者通過向其他相當簡單的模式語言添加了一個新的匹配模式來解決了這個問題。查看http://www.lua.org/pil/20.2.html中的最下面幾行!

+1

Perl的遞歸模式可以處理嵌套的分隔符。 – newacct 2009-12-23 03:36:55

+0

糟糕!修正了,謝謝。 – 2009-12-23 05:15:19

1

下面的Perl的正則表達式匹配的括號:

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

然而,你到這一點的時候,你不是在技術上使用「常規」表現了。

+3

更重要的是,您不再使用Ruby。 – 2009-12-23 04:03:57

+0

很漂亮!在擺弄它之後,我發現它的Ruby(1.9/Oniguruma)版本:/(? \((?:[^ \(\)] ++ | \ g )* \))/ – 2011-06-16 01:31:22

2

這樣做的問題是,包含嵌套的括號(或實際上什麼嵌套,督察任何需要遞歸)語言不經常,他們至少是上下文無關的。這意味着它們不能用正則語法來描述。正則表達式是常規語法的簡潔表示法。人類,嵌套括號不能用正則表達式來描述。

但是,我們不是在這裏談論正則表達式,我們正在談論Regexp s。雖然它們的語義和語法(非常)鬆散地基於正則表達式,但它們非常不同,特別是功能更強大。根據您使用的Regexp的特定風格,它們可能會也可能不會表達遞歸,從而解析嵌套的括號。 Perl Regex,例如可以解析嵌套括號。我不確定Ruby的Regexp是否可以,但我真的不在乎,因爲Regexp比正則表達式更強大的方式通常是通過將越來越多的語法綁定到它們上來實現的。

這使得在不可理解的怪物中設計爲簡單的正則表達式變得簡單。 (如果你能在什麼Perl的Regex張貼@Anon呢,然後再爲它一眼就能看出,但我不能,因此我不喜歡使用它。)

我更喜歡使用更強大的分析器,而不是複雜的Regexp

在這種情況下,你有一個上下文無關的語言,因此你可以使用一個非常簡單的遞歸下降解析器。你可以通過處理那些的正則表達式的子部分來進一步簡化你的遞歸下降解析器。最後,如果你更換遞歸與迭代+突變遞歸下降解析器,並巧妙地利用Ruby的布爾語義,整個解析器獲取基本上濃縮到這個單行:

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

我不認爲太糟糕了。

這裏有一些額外的刪除重複的空白整個事情和測試套件(當然):

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