【问题标题】:Removing text within parentheses (parentheses within parentheses prob)删除括号内的文本(括号内的括号概率)
【发布时间】:2009-12-23 02:38:32
【问题描述】:

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

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

这很好用,直到我有一个句子,例如:

"This is (a test (string))"

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

【问题讨论】:

  • 如果像(foo) bar)这样的开始和结束标签的数量不相等或者没有像foo) (bar这样的对怎么办?
  • 我不需要考虑这个场景。

标签: ruby regex string


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    看起来你需要贪心,删除?

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

    这使它转到最后一个 ) 而不是第一个。但是,它不会捕获嵌套,因为正则表达式无法做到这一点。

    【讨论】:

    • 没有为this is (in (parentheses)) and (so is this) text做它应该做的事情;)
    • 转义括号从来都不是问题的一部分; OP 做到了,但反斜杠没有出现,因为他没有应用正确的源代码格式。
    【解决方案3】:

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

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

    这会将原本设计简单的正则表达式变成难以理解的怪物。 (如果你一眼就知道@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
    

    【讨论】:

      【解决方案4】:

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

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

      但是,当您到达这一点时,从技术上讲,您已不再使用“常规”表达式。

      【讨论】:

      • 太漂亮了!在摆弄它之后,我找到了它的 Ruby (1.9/Oniguruma) 版本: /(?((?:[^()]++|\g)*))/
      【解决方案5】:

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

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

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

      【讨论】:

      • Perl 的递归模式可以处理嵌套的分隔符。
      猜你喜欢
      • 2013-11-17
      • 1970-01-01
      • 1970-01-01
      • 2021-06-07
      • 2017-07-06
      • 1970-01-01
      • 2018-12-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多