php正则获取字符串指定标签含嵌套标签的内容?

新手上路,请多包涵

有如下字符串,嵌套if中有可能有多个:

$str = "
{if 'a'}
    111111
    {if 'c'}33333{/if}
    {if 'd'}44444{/if}
    ......
{/if}
{if 'b'}22222{/if}";

希望得到,最外层的所有{if xx}{/if}标签的内容:

[
"{if 'a'}
    111111
    {if 'c'}33333{/if}
    {if 'd'}44444{/if}
    ......
{/if}",
"{if 'b'}22222{/if}"
]
阅读 1.8k
1 个回答

不光要简单的正则,还要配合代码进行处理

<?php

$str = "
{if 'a'}
    111111
    {if 'c'}33333{/if}
    {if 'd'}44444{/if}
    ......
{/if}
{if 'b'}22222{/if}

{if 'b2'}
    5555
    {if 'b'}
        6666
    {/if}
    777
{/if}
";

// 后面的 flag 表示记录偏移量
preg_match_all('!({/?if)!', $str, $matches, PREG_OFFSET_CAPTURE);
// 用数组来模拟栈
$stack  = [];
$top    = null;
$result = [];
foreach ($matches[0] as [$match, $offset]) {
    // 判断匹配到的如果是 {if 开始
    if ($match === '{if') {
        $stack[] = $offset;
        // 记录开始的位置
        if ($top === null) {
            $top = $offset;
        }
        // 如果不是 这里简单判断了 {if 就是 {/if
    } else {
        // 从栈底部拿一个出来
        $pop = array_pop($stack);
        // 如果取出来的是 null 就说明存在多余的 {/if 标签
        if ($pop === null) {
            throw new \Exception('语法错误,存在多余的 {/if} 标签');
        }
        // 如果取完后栈空了
        if (empty($stack)) {
            // offset 是匹配到 {/if 的开始(前面)位置,所以要加上 {/if 的长度
            $newOffset = $offset + strlen($match);
            // 从顶部到当前的偏移就是这个 if 里的内容了
            $result[] = substr($str, $top, $newOffset);
            // 存新的 top 开始下一轮,因为这里的 newOffset 是到上一段结束的位置,而要新位置开始,所以要 +1
            $top = $newOffset + 1;
        }
    }
}
// 如果运行完了,栈里面还有东西,那就说明缺少一个 {/if 标签。
if (!empty($stack)) {
    throw new \Exception('语法错误,存在未闭合的 {if} 标签');
}
// 打印结果。
var_dump($result);
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题