3

如何使用 php 进入嵌套大括号?

例子:

{{ text1 {{text2 text3 {{text4}} text5}} }}

应该输出

1- text1 {{text2 text3 {{text4}} text5}}
2- text2 text3 {{text4}} text5
3- text4
4

3 回答 3

5

这需要跟踪括号的数量,并且不能使用正则表达式来完成。您必须为此创建自己的解析器逻辑。正则表达式不是解析器,抱歉。

这是另一个与我的回答相同的类似问题

这是一个关于构建解析的 SO(在 Java 中,但它应该翻译得足够好)

于 2012-07-02T12:59:27.500 回答
2

与 Perl 一样,PCRE 可以将嵌套结构匹配到任意深度(仅受内存限制 - 见下文)。这是一个经过测试的脚本:

正则表达式匹配嵌套括号

<?php // test.php Rev:20120702_1100

$re_nested_double_bracket ='% # Rev:20120702_1100
    # Match {{...{{...}}...}} structure with arbitrary nesting.
    \{\{                      # Opening literal double bracket.
    (                         # $1: Contents of double brackets.
      (?:                     # Group for contents alternatives.
        [^{}]++               # Either one or more non-brackets,
      | (?R)                  # or a nested bracket pair,
      | \{                    # or the start of opening bracket
        (?!\{)                # (if not a complete open bracket),
      | \}                    # or the start of closing bracket.
        (?!\})                # (if not a complete close bracket).
      )*                      # Zero or more contents alternatives.
    )                         # End $1: Contents of double brackets.
    \}\}                      # Closing literal double bracket.
    %x';

$results = array(); // Global array to receive results.

// Recursively called callback routine adds to $results array.
function _bracket_contents_callback($matches) {
    global $results, $re_nested_double_bracket;
    $results[] = $matches[1];
    preg_replace_callback($re_nested_double_bracket,
        '_bracket_contents_callback', $matches[1]);
    return $matches[0]; // Don't modify string.
}

$input = file_get_contents('testdata.txt');
preg_replace_callback($re_nested_double_bracket,
    '_bracket_contents_callback', $input);

$count = count($results);
printf("There were %d matches found.\n", $count);
for ($i = 0; $i < $count; ++$i) {
    printf("  Match[%d]: %s\n", $i + 1, $results[$i]);
}
?>

当针对原始帖子中的测试数据运行时,正则表达式匹配的内容如下:

示例输出:

There were 3 matches found.
Match[1]: text1 {{text2 text3 {{text4}} text5}}
Match[2]: text2 text3 {{text4}} text5
Match[3]: text4

请注意,此正则表达式匹配最外面的一组可能嵌套的括号,并将$1括号之间的内容捕获到组中。该脚本利用该preg_replace_callback()函数递归匹配并将嵌套括号内容添加到结果数组。

“任意深度”请注意,此解决方案将嵌套括号匹配到任何“任意深度”,但始终受到系统内存、可执行堆栈大小和 PHP以及pcre.backtrack_limit配置变量的限制。请注意,如果主题字符串太大和/或对于给定的主机系统嵌套太深,则此正则表达式解决方案肯定会失败。PHP/PCRE 库甚至可能导致正在运行的可执行文件产生堆栈溢出、分段错误和程序崩溃!有关如何以及为什么会发生这种情况(以及如何避免它并优雅地处理此类错误)的深入讨论,请参阅我对相关问题的回答: Preg_match 函数中的 RegExp 返回浏览器错误pcre.recursion_limitmemory_limitPHP 正则表达式:这段代码有什么问题吗?.

注意:这个问题(和我的答案)几乎与以下内容相同:使用正则表达式解析专有标签语法 ​​- 如何检测嵌套标签?,但在这个答案中,提出了一个更完整的解决方案,它递归地匹配并存储所有嵌套的括号内容。

于 2012-07-02T14:35:02.057 回答
0

我找到了我正在寻找的答案并将其放在这里,以便每个人都可以使用它。它确实非常简单,仅在一行中:

  $text1=preg_replace("/\{\{(([^{}]*|(?R))*)\}\}/",'',$text1);

它会搜索并用你想要的任何内容替换所有 {{text}}。您还可以使用 preg_match_all 将它们全部放在一个数组中。

于 2012-07-07T07:31:59.830 回答