2009-12-23 270 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