这个正则表达式
/\(.*\)/
将匹配匹配的括号,但不匹配字符串中的最后一个括号。是否有正则表达式扩展或类似的东西,具有适当的语法允许这个?例如:
there are (many (things (on) the)) box (except (carrots (and apples)))
/OPEN(.*CLOSE)/
应与(many (things (on) the))
可能有无限级别的括号。
答案 0 :(得分:7)
如果你只有一个级别的括号,那么有两种可能性。
选项1:使用不合理的重复:
/\(.*?\)/
当它遇到第一个)
时会停止。
选项2:使用否定字符类
/\([^)]*\)/
这只能重复不是)
的字符,因此它必然不会超过第一个右括号。由于性能原因,通常首选此选项。此外,此选项更容易扩展以允许转义括号(以便您可以匹配此完整字符串:(some\)thing)
而不是丢弃thing)
)。但这可能很少需要。
但是如果你想要嵌套结构,这对于正则表达式来说通常过于复杂(尽管像PCRE这样的一些版本支持递归模式)。在这种情况下,您应该自己查看字符串并计算括号,以跟踪当前的嵌套级别。
正如关于这些递归模式的旁注:在PCRE中(?R)
只表示整个模式,因此将其插入某处会使整个事物递归。但是,括号中的每个内容必须与整个匹配的结构相同。此外,实际上不可能对此进行有意义的一步替换,以及在多个嵌套级别上使用捕获组。总而言之 - 你最好不要使用正则表达式来嵌套结构。
更新:由于您似乎渴望找到正则表达式解决方案,因此以下是使用PCRE匹配示例的方法(PHP中的示例实现):
$str = 'there are (many (things (on) the)) box (except (carrots (and apples)))';
preg_match_all('/\([^()]*(?:(?R)[^()]*)*\)/', $str, $matches);
print_r($matches);
结果
Array
(
[0] => Array
(
[0] => (many (things (on) the))
[1] => (except (carrots (and apples)))
)
)
模式的作用:
\( # opening bracket
[^()]* # arbitrarily many non-bracket characters
(?: # start a non-capturing group for later repetition
(?R) # recursion! (match any nested brackets)
[^()]* # arbitrarily many non-bracket characters
)* # close the group and repeat it arbitrarily many times
\) # closing bracket
这允许无限的嵌套级别以及无限的并行级别。
请注意,无法将所有嵌套级别作为单独的捕获组。你将始终只是获得最内层或最外层的组。此外,不能像这样进行递归替换。
答案 1 :(得分:2)
正则表达式不足以找到匹配的括号,因为括号是嵌套结构。但是,存在一种简单的算法来查找匹配的括号,这在this answer。
中有描述如果您只是想在表达式中找到第一个右括号,则应该在正则表达式中使用非贪心匹配器。在这种情况下,正则表达式的非贪婪版本如下:
/\(.*?\)/
答案 2 :(得分:1)
给定一个包含嵌套匹配括号的字符串,您可以将最里面的集与此(非递归JavaScript)正则表达式匹配:
var re = /\([^()]*\)/g;
或者您可以使用此(递归PHP)正则表达式匹配最外层的集合:
$re = '/\((?:[^()]++|(?R))*\)/';
但是你不能轻易地匹配最里面和最里面之间的匹配括号集。
另请注意,(天真且经常遇到的)表达式:/\(.*?\)/
将始终不正确匹配(最内层和最外层匹配的集合)。