用于检查字符串是否具有不匹配括号的正则表达式?

时间:2009-02-18 20:08:07

标签: php regex

在PHP脚本中,我应该使用什么正则表达式来检查字符串中不匹配的括号?我想要允许的事情包括:

  • 这是(ok)
  • 这是(好)

我想阻止的事情:

  • 这是坏事(
  • 这也是(不好
  • 这是(糟糕的)(

谢谢!

更新:你们都摇滚。使用正则表达式执行此操作似乎比应有的更复杂,而这些二级答案是使stackoverflow美观的原因。感谢链接和伪代码。我不确定是谁给出了答案,所以我向每个答案我都不能接受的人道歉。

8 个答案:

答案 0 :(得分:23)

正则表达式不适合这项工作。手动扫描字符串。

的伪代码:

depth = 0
for character in some_string:
    depth += character == '('
    depth -= character == ')'
    if depth < 0:
       break

if depth != 0:
   print "unmatched parentheses"

答案 1 :(得分:21)

可以使用正则表达式执行此操作 - PHP使用的PCRE允许递归模式。 PHP手册提供的example几乎完全符合您的要求:

\(((?>[^()]+)|(?R))*\)

只要它以括号开头和结尾,它就匹配任何正确的带括号的子字符串。如果你想确保整个字符串是平衡的,允许字符串 “wiggedy(wiggedy)(wiggedy(wack))”,这就是我想出的:

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

这是对模式的解释,这可能比混淆更具启发性:

^             Beginning of the string
(             Start the "balanced substring" group (to be called recursively)
  (?:         Start the "minimal balanced substring" group
    [^()]     Minimal balanced substring is either a non-paren character
    |         or
    \((?1)\)  a set of parens containing a balanced substring
  )           Finish the "minimal balanced substring" group
  *           Our balanced substring is a maximal sequence of minimal
              balanced substrings
  +           Don't backtrack once we've matched a maximal sequence
)             Finish the "balanced substring" pattern
$             End of the string

有很多关于效率和正确性的考虑因素都会产生这些类型的正则表达式。小心。

答案 2 :(得分:8)

使用正则表达式无法实现此目的。大括号匹配需要递归/计数功能,这在正则表达式中是不可用的。你需要一个解析器。

此处提供了更多详细信息:http://blogs.msdn.com/jaredpar/archive/2008/10/15/regular-expression-limitations.aspx

答案 3 :(得分:4)

同意REGEX无法做到的事实。但是,您可以执行以下操作:

<?php

$testStrings = array( 'This is (ok)', 'This (is) (ok)', 'This is )bad(', 'This is also (bad', 'This is (bad (too)' );

foreach( $testStrings as $string ) {
    $passed = hasMatchedParentheses( $string ) ? 'passed' : 'did not pass';
    echo "The string $string $passed the check for matching parenthesis.\n";
}

function hasMatchedParentheses( $string ) {
    $counter = 0;
    $length = strlen( $string );
    for( $i = 0; $i < $length; $i ++ ) {
        $char = $string[ $i ];
        if( $char == '(' ) {
            $counter ++;
        } elseif( $char == ')' ) {
            $counter --;
        }
        if( $counter < 0 ) {
            return false;
        }
    }
    return $counter == 0;
}

?>

答案 4 :(得分:3)

您的示例不包含任何嵌套括号...如果您不关心嵌套,则可以使用以下表达式完成此操作:

^[^()]*(?:\([^()]*\)[^()]*)*$

这将匹配“允许”列表中的所有字符串,并且会对“阻止”列表中的字符串失败。但是,对于具有嵌套括号的任何字符串也会失败。例如“这(是(不)确定)”

正如其他人已经指出的那样,如果需要处理嵌套,正则表达式不是正确的工具。

答案 5 :(得分:2)

为了扩展JaredPar的答案,不使用正则表达式解决问题并不是很困难,只需编写一个函数来检查字符串中的每个字符并递增/递减计数器。如果你找到“(”,增加它,如果你找到“)”,则减少它。如果计数器低于0,则可以中断,字符串无效。当你处理完整个字符串时,如果计数器不是0,则有一个不匹配的左括号。

答案 6 :(得分:1)

为什么使用正则表达式无法实现

其他答案都是正确的,但我只想插入理论计算机科学的插件......这是一个知道理论给出实际实际优势的案例。

正则表达式对应于确定性有限自动机(DFA),但是匹配需要无上下文语法,可以将其实现为有限自动机(PDA),但不能通过DFA实现。

正因为如此,没有大量的额外脑力劳动,我们知道答案是否定的,我们不必担心我们只是忽略了一些东西。所以,你可以对上面的答案充满信心,不要担心作者在给出答案时会忽视某些东西。

几乎所有的编译器书籍都会讨论这个问题,这里有一个快速概述:

http://books.google.com/books?id=4LMtA2wOsPcC&pg=PA94&lpg=PA94&dq=push-down+finite+automata&source=bl&ots=NisYwNO1r0&sig=ajaSHFXwpPOWG8IfbcfKoqzS5Wk&hl=en&ei=m26cSdf6DZGYsAPB-6SsAg&sa=X&oi=book_result&resnum=6&ct=result

答案 7 :(得分:0)

使用没有正则表达式的php:

function analyse($input){
    $len = strlen($input);
    $depth = 0;
    for ($i = 0; $i < $len; $i++) {
        $depth += $input[$i] == '(';
        $depth -= $input[$i] == ')';
        if ($depth < 0) break;
    }
    if ($depth != 0) return false;
        else return true;
}
$check_nestled = analyse('(5 * 2) + ((2 + 2) - 4)');
if($check_nestled){
    // do stuff, everything is ok
}