正则表达式找到无与伦比的括号

时间:2012-02-15 20:06:58

标签: ruby regex

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

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

我提出了一个正则表达式,使用负向前瞻找到了无与伦比的开括号\((?![^)]+\)),但我似乎无法找出无与伦比的结束括号所需的对立面。

  

编辑:找到无法匹配的开括号的上述正则表达式无法正常工作。例如。它将错过多个开括号后跟一个右括号的情况(另见注释)

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

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

请注意,字符串可以包含任何类型的字符,包括引号,短划线等。

3 个答案:

答案 0 :(得分:10)

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

答案 1 :(得分:4)

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

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

答案 2 :(得分:1)

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等真正的解析器来完成此任务。