删除括号内的文本(括号中的括号)

时间:2009-12-23 02:38:32

标签: ruby regex string

我正在尝试删除括号内的文本(以及括号本身),但是在括号内有圆括号的情况下遇到问题。这是我正在使用的方法(在Ruby中):

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

并且一直有效,直到我有一句话如下:

"This is (a test (string))"

然后是上面的扼流圈。任何人都知道如何做到这一点?我完全被难倒了。

5 个答案:

答案 0 :(得分:10)

通过删除?

,您看起来需要贪婪
>> "This is (a test (string))".gsub(/\(.*\)/, "")
=> "This is "

这使它转到最后)而不是第一个{{1}}。但是,它不会捕获嵌套,因为正则表达式不能这样做。

答案 1 :(得分:10)

一种方法是从内到外替换括号组:

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

答案 2 :(得分:2)

这个问题是包含嵌套括号的语言(或者实际上任何嵌套,IOW任何需要递归的东西)不是常规的,它们至少是无上下文的。这意味着它们不能用常规语法来描述。正则表达式是常规语法的紧凑表示法。因此,正则表达式无法描述嵌套括号。

但是,我们不是在谈论正则表达式,我们讨论的是Regexp。虽然它们的语义和语法(非常)松散地基于正则表达式,但它们是完全不同的,尤其是更强大。根据您使用的Regexp的特定风格,它们可能会或可能不会表达递归,从而解析嵌套括号。 Perl Regex,例如可以解析嵌套括号。我不确定Ruby的Regexp是否可以,但我真的不在乎,因为Regexp比正则表达式更强大的方式通常是通过将越来越多的语法用于它们来实现的。 / p>

这使得在难以理解的怪物中设计简单的正则表达式。 (如果你能一眼就看出@Anon发布的Perl Regex是做什么的,那就去吧。但我不能,因此我不愿意使用它。)

我更喜欢使用更强大的解析器,而不是复杂的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

答案 3 :(得分:1)

以下Perl正则表达式将匹配平衡括号:

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

然而,当你达到这一点时,你在技术上不再使用“常规”表达了。

答案 4 :(得分:0)

如果最外层只有一组括号,那么jleedev的答案将起作用;在这种情况下,使那些括号的内部表达式贪婪应该可以解决问题。

然而,也许有点令人惊讶的是,在 Perl, Java,Ruby和其他一些语言中定义的正则表达式grepsed不适合处理有这个问题。处理嵌套分隔符的一般情况没有正则表达式。当您想要使用正则表达式处理HTML或XML时,这就是为什么SO会对您大吼大叫的原因之一。

有趣的是,Lua语言的创建者通过在其他相当简单的模式语言中添加新的匹配模式来解决这个问题。查看http://www.lua.org/pil/20.2.html中的少数几行!