【问题标题】:Regex to find unmatched parentheses正则表达式查找不匹配的括号
【发布时间】:2012-02-15 20:06:58
【问题描述】:

我需要一个正则表达式,它可以在可能包含匹配括号的字符串中找到任何不匹配的大括号(打开或关闭)。

stackoverflow 上存在这个问题,但我还没有找到有效的基于正则表达式的解决方案。

我想出了一个正则表达式,它使用负前瞻查找不匹配的左大括号 \((?![^)]+\)),但我似乎无法找出不匹配的右大括号所需的相反的表达式。

编辑:上述用于查找不匹配的左大括号的正则表达式无法按预期工作。例如。它会错过多个左大括号后跟一个右大括号的情况(另请参见 cmets)

这是我在 Rubular 上试验的测试字符串:

one) ((two) (three) four) (five)))

请注意,字符串可以包含任何类型的字符,包括引号、破折号等。

【问题讨论】:

  • 那是因为在一般情况下没有基于正则表达式的解决方案。这和你cannot parse XML with regex 的原因相同(同样,在一般情况下)。
  • 真的必须是正则表达式吗?为什么不使用string.each_char { |c| ... } 进行简单循环?
  • 没有严格的正则表达式语言可以。但是像 PCRE 这样的常见扩展正则表达式可能可以。见stackoverflow.com/questions/562606/…
  • 您的正则表达式并没有按照您的想法执行。它会找到任何( 后面没有)。例如((2+3) 将不会显示任何不匹配的(,因为它们都在某个时间点后面跟着)
  • 大卫,你说得对。负前瞻只是确保有一个右括号 somewhere 并且会错过您提到的情况。

标签: ruby regex


【解决方案1】:

简短的回答是,您无法使用正则表达式找到不匹配的括号。正则表达式编码regular languages,而所有正确匹配括号的语言是context-free language

【讨论】:

    【解决方案2】:

    这是一种基于正则表达式的解决方案 :)

    def balanced?( str, open='(', close=')' )
      re = Regexp.new( "[\\#{open}\\#{close}]" )
      str.scan(re).inject(0) do |lv,c|
        break :overclosed if lv < 0
        lv + (c==open ? 1 : -1)
      end == 0
    end
    
    s1 = "one) ((two) (three) four) (five)))"
    s2 = "((one) ((two) (three) four) (five))"
    s3 = "((one) ((two) (three) four) (five)"
    
    puts balanced?(s1), #=> false
         balanced?(s2), #=> true
         balanced?(s3)  #=> false
    

    【讨论】:

      【解决方案3】:

      Ruby 的 Oniguruma 库可以解析 LALR(n) 语法,包括 HTML。引用README

        r = Regexp.compile(<<'__REGEXP__'.strip, Regexp::EXTENDED)
        (?<element> \g<stag> \g<content>* \g<etag> ){0}
        (?<stag> < \g<name> \s* > ){0}
        (?<name> [a-zA-Z_:]+ ){0}
        (?<content> [^<&]+ (\g<element> | [^<&]+)* ){0}
        (?<etag> </ \k<name+1> >){0}
        \g<element>
        __REGEXP__
      
        p r.match('<foo>f<bar>bbb</bar>f</foo>').captures
      

      上面的代码当然比真正的 HTML 解析器简单得多,但它匹配嵌套的标签。此外,您应该注意,制作一个非常慢的正则表达式非常简单(解析 80 个符号的字符串在几分钟的范围内)。

      最好使用像Treetop 这样的真正解析器来完成这项任务。

      【讨论】:

        猜你喜欢
        • 2011-04-05
        • 2013-06-19
        • 1970-01-01
        • 2011-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多