是否有能够解析匹配符号的正则表达式?

时间:2012-10-28 20:07:33

标签: regex string parsing

这个正则表达式

/\(.*\)/

将匹配匹配的括号,但不匹配字符串中的最后一个括号。是否有正则表达式扩展或类似的东西,具有适当的语法允许这个?例如:

there are (many (things (on) the)) box (except (carrots (and apples)))

/OPEN(.*CLOSE)/应与(many (things (on) the))

匹配

可能有无限级别的括号。

3 个答案:

答案 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))*\)/';

但是你不能轻易地匹配最里面和最里面之间的匹配括号集。

另请注意,(天真且经常遇到的)表达式:/\(.*?\)/将始终不正确匹配(最内层和最外层匹配的集合)。