【问题标题】:Regex recursive code block content正则表达式递归代码块内容
【发布时间】:2015-08-02 07:12:43
【问题描述】:

我需要使用 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。折腾了几个小时,还是没搞定。

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

【问题讨论】:

  • 听起来如果没有 regex 可以更容易地完成,或者说,使用 regex 仅查找开始和结束标签。有什么理由要在正则表达式中完成所有操作?
  • 据我了解,嵌套括号没有正则表达式。您可以使用更复杂的代码,将括号连续替换为任何字符,而括号仍在字符串中。

标签: php regex recursion blade


【解决方案1】:

要捕获外部@embed 和嵌套的recursive regex

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

(?0) 粘贴模式。见test at regex101。匹配时替换为捕获的$1

$res = array();

while (preg_match_all($pattern, $str, $out)) {
  $str = preg_replace($pattern, "$1", $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
  • (?&gt; 使用非捕获 atomic group 进行交替:
  • 在:(?!@(?:end)?embed). 一个字符 that starts not @embed@endembed 之间交替 |(?0) 或者从头开始粘贴模式。 )* 整件事不限次数。
  • 匹配文字@endembed

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

【讨论】:

    【解决方案2】:

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

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

    试试regex101

    【讨论】:

      猜你喜欢
      • 2012-01-16
      • 1970-01-01
      • 2012-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-10
      • 2015-05-30
      相关资源
      最近更新 更多