使用Javascript,假设我有一个类似(1)(((2)(3))4)
的字符串,我是否可以使用正则表达式匹配(1)
和(((2)(3))4)
,还是需要做一些更复杂的事情?
如果您搜索["((2)(3))","4"]
,理想情况下正则表达式会返回((2)(3))4
。实际上这确实是一个要求。重点是将事物分组到需要首先处理的块中,就像括号在数学中的工作方式一样。
答案 0 :(得分:2)
No, there is no way to match only top level parentheses with regex
仅查看顶级并不会使问题比递归结构的一般“解析”更容易。 (见this relevant popular SO question并给出了一个很好的答案)。
这是一个简单直观的原因,为什么Regex无法解析任意级别的嵌套:
要跟踪嵌套水平,必须计算。如果一个人想要跟踪任意级别的嵌套,那么在运行程序时需要一个任意大的数字。
但正则表达式正是 DFA 可以实现的那些,即Deterministice 有限自动机。它们只有有限个状态。因此,他们无法跟踪任意大数字。
这个论点也适用于您对顶级括号感兴趣的特定问题。
要识别顶级括号,您必须跟踪其中任何一个之前的任意嵌套:
((((..arbitrarily deep nesting...))))((.....)).......()......
^toplevel ^^ ^ ^^
所以,是的,你需要比正则表达更强大的东西。
虽然如果你非常实用,但对于你的具体应用,你可能会说你不会遇到任何比1000更深的嵌套(所以你可能愿意去使用正则表达式,这也是一个非常实际的事实,任何识别嵌套级别超过2的正则表达式基本上是不可读的。
答案 1 :(得分:1)
嗯,这是一种方法。正如Jo So指出的那样,你无法在javascript中使用无限量的递归来实现它,但你可以很容易地做出任意递归的东西。我不确定性能如何扩展。
首先我发现你需要递归。然后我意识到你可以让你的正则表达式递归'通过递归复制和粘贴,就像这样(为了清晰起见使用花括号):
启动正则表达式
在括号中查找不是括号的内容。
/{([^{}])*}/g
然后将整个正则表达式复制并粘贴到自身内部! (我将它隔开,这样你就可以看到粘贴的位置。)所以现在它基本上就像a( x | a( x )b )b
/{([^{}] | {([^{}])*} )*}/g
这将为您提供一个级别的递归,您可以以这种方式继续恶作剧,实际上每次递增的次数加倍:
//matches {4{3{2{1}}}}
/{([^{}]|{([^{}]|{([^{}]|{([^{}])*})*})*})*}/g
//matches {8{7{6{5{4{3{2{1}}}}}}}}
/{([^{}]|{([^{}]|{([^{}]|{([^{}]|{([^{}]|{([^{}]|{([^{}]|{([^{}])*})*})*})*})*})*})*})*}/g
最后,我只需在表达式的末尾添加|[^{}]+
以匹配完全在括号之外的内容。疯狂,但它适合我的需要。我觉得可能有一些聪明的方法将这个概念与递归函数结合起来以获得一个真正的递归匹配器,但我现在无法想到它。
答案 2 :(得分:0)
如果 ,您可以确保括号是平衡的(我确定还有其他资源可以根据需要为您回答该问题) 和 ,如果您很乐意通过“顶级”找到本地最大值和全局最大值 然后 要做的就是找到任何内容,这些内容以方括号开头,以方括号结尾,并且两者之间没有中间的方括号:
我认为以下应该为您做到这一点,并有益地将所有“顶级”内容分组:
\(([^\(]*?)\)
该内容可能并非全部处于同一“级别”,但是如果您认为嵌套括号描述的是树的分支,则正则表达式将返回给您叶子。如果您先对文本进行预处理并以括号括起来,并且符合先前的假设,则可以保证始终获得至少一个“叶子”。