javascript - 请问正则如何匹配多层成对的括号?
ringa_lee
ringa_lee 2017-04-11 12:57:31
[JavaScript讨论组]
"()" => returns true
")(()))" => returns false
"(" => returns false
"(())((()())())" => returns true

形如这种,我可以做到匹配2,3层的没问题,但是层数多了就不知道该怎么办了
ringa_lee
ringa_lee

ringa_lee

全部回复(11)
PHPz

如果你要通过正则表达式来完成这个匹配比较困难。但是如果你纯粹时想看看括号是不是左右成对匹配,我想你可以用进出栈的方式进行判断,这比正则来的简单快捷。

PHPz

维护一个计数器,如果是左括号加1,右括号减一,最后判断计数器是否等于0。

function match(str) {
    var n = 0;
    for (s of str) {
        if (s === '(') {
            n++;
        } 
        if (s === ')') {
            if (n === 0) {
                return false;
            }
            n--;
        }
    }
    return n === 0;
}
PHP中文网

为什么我记得括号匹配是2型文法,正则表达式是3型文法,所以这个是不可能的呢……

乔姆斯基文法

高洛峰
str && str.replace(/\(\)/g, '') === '';
迷茫

如果你用 .NET 平台,可以用平衡组来匹配这种嵌套的结构,某些支持任意层嵌套的正则引擎应该也可以,不过这种语法不一定是标准的正则语法。

PHP中文网

1.先检测是不是左括号先出现
2.分别统计左右括号的个数,判断左右括号数目是否相等

以上方法有缺陷,下面使用逐级替换来实现

$str = "((()))";

while(strrpos($str, '()')){
    $str = str_replace($str, '()', '');
}

if(strlen($str) == 0){
   echo "match";
} else {
   echo "no match";
}
怪我咯

我认为这个问题的关键在于你必须遍历一遍这个字符串,在每次 ')' 出现时检查是否有空余的 '(' 与之对应。
那么我们可以在遍历的时候维护一个空余的左括号计数来解决这个问题。
一个c++的示例:

#include <cstdio>
#include <string>

bool isValid(const std::string& str) {
    if (str.empty())
        return false;

    int left = 0;

    for (auto itr = str.begin(); itr != str.end(); itr++) {
        if (*itr == '(') {
            left++;
        } else if(*itr == ')') {
            left--;
            if (left < 0) 
                return false;
        } else {
            return false;
        }
    }
    return (left == 0);
}
阿神
#!/usr/bin/env perl

my $levelN;
$levelN = qr/\(([^()] | (??{$levelN}))*\)/x;

my @list = (
    '()',
    ')(()))',
    '(((((((())))))))',
    '(())((()())())',
    '(()))()',
    '()()'
);
foreach my $text (@list) {
    if ($text =~ m/^($levelN)+$/x) {
        print "found matche: $text\n";
    }
}

perl的动态正则可以实现,javascript好像也支持动态正则,具体可以查一下

参见:<精通正则表达式:用动态正则表达式结构匹配嵌套结构 P328>

黄舟

不能。

因为多层嵌套的括号是上下文无关文法,正则表达式只能匹配正则语言。

这个恰好不属于正则语言,可以证明。

迷茫

正则是会一点,但是看这个估计很难实现吧,实际上解决问题就可以了,不一定要用正则的,下面这种方法肯定可以,希望楼主采纳。
思路:用0+0的方式填充括号里面的内容,最后用eval执行,如果执行成功则左右括号是一对一,否则失败。

        var abc = "(())((()())())";
        var a = abc.replace(/\)/g,"+)").replace(/\)\(/g,")+(").replace(/\(\+/g,"(0+").replace(/\+\)/g,"+0)");
        var flag;
        try{
            var b = eval(a);
            flag = true;
        }catch (e){
            flag = false;
        }
        console.log(flag);
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号