2012-02-15 194 views
3

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

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

我想出了一个正则表达式,发现无与伦比的开放大括号\((?![^)]+\))使用负向预测,但我似乎无法弄清楚无与伦比的大括号所需的相反之处。

编辑:上述正则表达式来查找不匹配开放括号按预期不起作用。例如。它会怀念在多个打开的括号后跟一个右括号的情况下(见评论)

这里是我一直在尝试与Rubular我的测试字符串:

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

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

+4

这是因为在一般情况下不存在基于正则表达式的解决方案。这与你[无法用正则表达式解析XML](http://stackoverflow.com/a/1732454/13)(同样在一般情况下)是一样的原因。 – 2012-02-15 20:09:14

+1

它真的必须是正则表达式吗?为什么不用'string.each_char {| c | ''? – 2012-02-15 20:10:18

+2

没有严格的正则表达式语言可以..但像PCRE常见的扩展正则表达式可能能够。请参阅http://stackoverflow.com/questions/562606/regex-for-checking-if-a-string-has-mismatched-parentheses – Kaganar 2012-02-15 20:15:14

回答

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 
+0

不错,谢谢:) – 2012-02-15 21:26:31

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这样的实际解析器。