正则表达式递归代码块内容

Regex recursive code block content

我需要使用 RegEx 获取 2 个指令(embedendembed)之间的内容。我当前的模式正确地做到了这一点 /(?<!\w)(\s*)@embed(\s*\(.*\))([\w\W]*?)@endembed/g.

但是,当指令嵌套时,它不能正确匹配块。 https://regex101.com/r/nL8gV5/2

@extends('layouts/default')

@section('content')
    <div class="row">
        <div class="col-md-6">
            @embed('components/box')
                @section('title', 'Box title')
                @section('content')
                    <h4>Haai</h4>
                    Box content
                @stop
            @endembed
        </div>
        <div class="col-md-6">
            @embed('components/box')
                @section('title', 'Box2 title')
                @section('content')

                    @embed('components/timeline')
                        @section('items')
                        @stop
                    @endembed

                @stop
            @endembed
        </div>
    </div>
@stop

期望的输出:

1:    
@section('title', 'Box title')
@section('content')
    <h4>Haai</h4>
    Box content
@stop

2:
@section('title', 'Box2 title')
@section('content')
    @embed('components/timeline')
        @section('items')
        @stop
    @endembed
@stop

3:
@section('items')
@stop

我尝试了各种模式,但我似乎无法做到正确。据我了解,我应该将 (R?) 递归标记与反向引用结合使用吗?更像是这样 https://regex101.com/r/nL8gV5/3。折腾了好几个小时,还是没搞定。

我做错了什么,正确的模式是什么?

我从一个例子中想出了这个递归正则表达式(来自这个 Whosebug answer):

(?=(@embed(?:(?>(?:(?!@embed|@endembed).)+)*|(?1))*@endembed))

regex101

上试用

要捕获外部 @embed 和嵌套的,请使用 recursive regex:

$pattern = '/@embed\s*\([^)]*\)((?>(?!@(?:end)?embed).|(?0))*)@endembed/s';

(?0) 处粘贴了图案。参见 test at regex101。匹配出时用捕获的 </code> 替换:</p> <pre><code>$res = array(); while (preg_match_all($pattern, $str, $out)) { $str = preg_replace($pattern, "", $str); $res = array_merge($res, $out[1]); }

这将为您提供最外层和嵌套的直到最内层。 Test at eval.in


没有任何捕获的基本递归模式很简单as this:

/@embed\b(?>(?!@(?:end)?embed\b).|(?0))*@endembed/s
  • 匹配文字 @embed 后跟 \b word boundary
  • (?> 使用非捕获 atomic group 进行交替:
  • 交替:(?!@(?:end)?embed).一个字符that starts not@embed@endembed |(?0) 或者从头开始粘贴模式。 )* 整个事情任意次数。
  • 匹配文字 @endembed

使用 s (PCRE_DOTALL) flag for making the dot 也匹配换行符