这个正则表达式
/\(.*\)/
不会匹配匹配的括号,而是字符串中的最后一个括号。是否有正则表达式扩展或类似的东西,具有允许这样做的适当语法?例如:
there are (many (things (on) the)) box (except (carrots (and apples)))
/OPEN(.*CLOSE)/
应该匹配(many (things (on) the))
括号可能有无限的层次。
如果你只有一层括号,那么有两种可能性。
选项 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
这允许无限嵌套级别以及无限并行级别。
请注意,不可能将所有嵌套级别作为单独的捕获组。您将始终只获得最内层或最外层的组。此外,像这样进行递归替换是不可能的。
正则表达式不足以找到匹配的括号,因为括号是嵌套结构。但是,有一个简单的算法可以找到匹配的括号,这在这个答案中有描述。
如果您只是想在表达式中找到第一个右括号,则应在正则表达式中使用非贪婪匹配器。在这种情况下,您的正则表达式的非贪婪版本如下:
/\(.*?\)/
给定一个包含嵌套匹配括号的字符串,您可以使用这个(非递归 JavaScript)正则表达式匹配最里面的集合:
var re = /\([^()]*\)/g;
或者你可以用这个(递归 PHP)正则表达式匹配最外层的集合:
$re = '/\((?:[^()]++|(?R))*\)/';
但是您不能轻松地匹配位于最内层和最外层之间的匹配括号集。
还要注意(天真和经常遇到的)表达式:/\(.*?\)/
将始终不正确地匹配(既不是最内层也不是最外层匹配集)。