如何匹配开始和结束大括号内的文本、标记和指定的属性


How to match text inside starting and closing curly brace, the tags and the specified attributes

我正在为我的CMS系统实现一个插件代码。类似于短代码的东西,但在许多情况下都适用。我想要一个管理员这样写代码的例子:

示例1:

{COMMAND_NAME}Strings of texts that conatains htmltags,symbols,just anything{/COMMAND_NAME}

示例2

{COMMAND_NAME}

示例3

{COMMAND_NAME{attriute1=value attribute2=value}}

示例4

{COMMAND_NAME{attriute1=value attribute2=value}}Strings of anything including texts, htmltags and anything at all {/COMMAND_NAME}

Regex可以匹配上面的字符串。从单个正则表达式模式中获取COMMAND_NAME,获取介于两者之间的文本,并获取结束{/COMMAND_NAME}

在正则表达式中,我想捕获COMMAND_NAME、属性(如果提供)、介于两者之间的文本(如果{COMMAND_NAME}有一个结束{/COMMAND_NAME})和结束{/COMMAND_NAME}(如果提供的话)。

看看我到目前为止做了什么,然后得出一些不完整的结果

$regex = #'{(RAW|ACCESS|DWNLINK|MODL)['{]{0,1}(['w'W's]*?)'}{0}'}(['w's]+)(['{/RAW|ACCESS|DWNLINK|MODL]*)'}#i
$strings = '<div class="blog-list-item blog"><header class="entry-title">
        <h1>Welcome to our website</h1>
    </header><article id="entry-72" class="entry post-72 page et-bg-layout-dark et-white-bg"><div class="jumbotron row">
<div class="col-md-8">
<ul>
<li>You have a pending job on your neck?&hellip;</li>
<li>Do your company need a website makeover ?&hellip;</li>
<li>Or a competitive web application ? ?&hellip;</li>
<li>Do you need a customized plugin, or a tweak ?&hellip;</li>
<li>Maybe you want a personal website ?&hellip;</li>
<li>Or a graphic for your new project ?&hellip;</li>
</ul>
<div class="bg-primary well">
<h4 class="text-center text-white shadow">Track your project as we work it         to perfection...</h4>
</div>
</div>
<div class="pull-right col-md-4">
<h4 class="bg-primary text-white well">Other services we offer</h4>
{ACCESS{type=500}}
<ul>
<li>SEO work for an existing website or new</li>
<li>Bulk SMS</li>
<li>E-currency exchange</li>
<li>Facebook AD</li>
<li>Google AD</li>
</ul>
{/ACCESS}</div>
{RAW{say=email,access=500}} {RAW} <a class="btn button large tall green"     href="client-area">Place new Job now as we deliver at the quickest   <em>reasonable time</em></a>{/RAW}</div></article></div>';
And doing a php var_dump, gives the following result:
array(5) {
  [0]=>
  array(1) {
    [0]=>
    string(224) "{ACCESS{type=500}}
<ul>
<li>SEO work for an existing website or new</li>
<li>Bulk SMS</li>
<li>E-currency exchange</li>
<li>Facebook AD</li>
<li>Google AD</li>
</ul>
{/ACCESS}</div>
{RAW{say=email,access=500}} {RAW}"
  }
  [1]=>
  array(1) {
    [0]=>
    string(6) "ACCESS"
  }
  [2]=>
  array(1) {
    [0]=>
    string(209) "type=500}}
<ul>
<li>SEO work for an existing website or new</li>
<li>Bulk SMS</li>
<li>E-currency exchange</li>
<li>Facebook AD</li>
<li>Google AD</li>
</ul>
{/ACCESS}</div>
{RAW{say=email,access=500}"
  }
  [3]=>
  array(1) {
    [0]=>
    string(1) " "
  }
  [4]=>
  array(1) {
    [0]=>
    string(4) "{RAW"
  }
}

这实际上不是我需要检索的。再次,我想捕获COMMAND_NAME,仅当提供属性时捕获属性,如果{COMMAND_NAME}具有结束{/COMMAND_NAME}则捕获介于两者之间的文本,如果提供则捕获结束{/COMMAND_NAME}。这意味着该命令可以是内联{COMMAND_NAME},也可以不是{COMMAND_NAME}某些字符串{/COMMAND_NAME},也可以是属性{COMMAND_NAME{attr1=value attr2=value2}}

此正则表达式将按照您指定的方式工作:

$regex = '~
#opening tag
'{(RAW|ACCESS|DWNLINK|MODL|'w+)
 #optional attributes
 (?>
     '{   ([^}]*)   }
 )?
}

#optional text and closing tag
(?:
    (   #text:= any char except "{", or a "{" not followed by /commandname
        [^{]*+
        (?>'{(?!/?'1[{}])[^{]*)*+
    )
    #closing tag
    (   '{/'1}   )
)?
~ix';

regex101演示


与您所拥有的相比:

首先,我使用了/x修饰符(在末尾),它忽略了空白和#comments

在开头的标签中,我使用了您的选项,但您也可以使用'w+来匹配任何命令名:

'{(RAW|ACCESS|DWNLINK|MODL|'w+)

对于可选属性,您有['{]{0,1}(['w'W's]*?)'}{0},这是一种使每个部分都可选的尝试。相反,我使用(?> group )?(参见非捕获组和原子组)使整个子模式可选(使用?量词)。

 (?>
     '{   ([^}]*)   }
 )?

同样的逻辑也应用于文本和结束标记,使其成为可选的。

您使用['w's]+来匹配文本,它匹配单词字符和空白,但无法匹配标点符号和其他字符。我本可以使用.*?,它也同样有效。然而,我使用了以下结构,它匹配相同,但性能更好:

    (   #text:= any char except "{", or a "{" not followed by /commandname
        [^{]*+
        (?>'{(?!/?'1[{}])[^{]*)*?
    )

最后,我使用'1匹配结束标签,这是对组1中匹配的文本(开始标签名称)的反向引用:

'{/'1}

假设:

  • 属性的引号(如"te}xt")中没有可能使其中断的大括号