PHP regexp - 检测未关闭的括号

时间:2016-06-01 17:31:58

标签: php regex substring

我需要检测字符串是否包含任何未闭合的尖括号。

我试图通过比较左右括号的数字来避免正则表达式:

if (substr_count($string, '<') !== substr_count($string, '>'))
{
    // Text contains unclosed angle brackets           
}

但是这种方法不会检测到这样的错误:

This is >b<BOLD>/b< word

5 个答案:

答案 0 :(得分:2)

  

但是这种方法不会检测到这样的错误:

因为只有当您想检查是否有相同数量的开始和结束括号时,计数才有意义。但是如果你想善待你的用户并指向他犯错的地方,那么计数就不够了你应该使用即堆栈(基于array_push()和{{1}的基于数组的堆栈就足够了)。使用堆栈,您可以在字符串上进行迭代,并在遇到左括号array_pop()时按下令牌,并在收到一个<时弹出一个令牌。在你的情况下:

>

你必须This is >b<BOLD>/b< word ,因为第一个是pop但是堆栈上什么都没有,所以这会触发错误。让我们修复那个括号并继续:

>

并运行

This is <b<BOLD>/b< word

依此类推......一旦你到达字符串的末尾并且你的堆栈不是空的,那么你知道最后发现的push -> ok push -> well if you allow nested brackets, then all is ok, otherwise stack must be empty prior pushing so this bracket is misplaced and you shall throw an error 错过了它的<对(如果你允许括号嵌套,那么逻辑需要告诉哪一个可能没有关闭可能会更复杂,有时会给出错误的结果(例如编译器有时会在类似的情况下做))。

如果您不打算允许嵌套括号,那么您可以使代码更简单,因为使用普通>变量来指示状态就足够了(即&#39; 0&#39;对于{{1 } {} integer代表<1代表初始状态)

答案 1 :(得分:2)

我不建议将正则表达式用于这样的任务。
快速编写一个简单的函数来检查字符串是否正确写入括号:

/**
* @param $str input string
* @returns boolean true if all brackets are properly opened and closed, false otherwise
*/
function checkBraces($str)
{
    $strlen = strlen($str); // cache string length for performance
    $openbraces = 0;

    for ($i = 0; $i < $strlen; $i++)
    {
        $c = $str[$i];
        if ($c == '<') // count opening bracket
            $openbraces++;
        if ($c == '>') // count closing bracket
            $openbraces--;

        if ($openbraces < 0) // check for unopened closing brackets
            return false;
    }

    return $openbraces == 0; // check for unclosed open brackets
}

使用此代码作为基础,实现检查以验证开始和结束括号的标记名称是否也匹配应该不会太难 - 但我会留给您: - )

答案 2 :(得分:1)

如果字符是“&lt;”,则一次循环字符串一个字符增加一个计数器,如果它是“&gt;”递减柜台。如果计数器变为负数或者当你通过字符串时计数器不为零,那么你有未闭合的括号。

答案 3 :(得分:1)

有一个PCRE正则表达式可以检查正确数量的平衡尖括号:

'~\A[^<>]*+(<(?>[^<>]|(?1))*+>[^<>]*+)++\z~'

请参阅regex demo

请参阅regular-expressions.info的Matching Balanced Constructs页面上的详细信息。

简而言之:

  • \A - 字符串开头
  • [^<>]*+ - 除<>以外的零个或多个字符
  • (<(?>[^<>]|(?1))*+>[^<>]*+)++ - 一次或多次出现
    • < - 打开<括号
    • (?>[^<>]|(?1))*+ - 除<>(参见[^<>])或整个第1组子模式(子程序调用{​​{1)以外的任何字符的0次或更多次出现}})
    • (?1) - 关闭>括号
    • > - 除[^<>]*+<以外的零个或多个字符
  • > - 字符串结束。

答案 4 :(得分:-1)

这是一个不允许嵌套括号的正则表达式。

/^([^<>]*<[^>]*?>[^<>]*)*$/m