【问题标题】:How to match text inside starting and closing curly brace, the tags and the specified attributes如何匹配开始和结束花括号内的文本、标签和指定的属性
【发布时间】:2015-11-21 08:13:30
【问题描述】:

我正在为我的 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}

正则表达式可以匹配上面的字符串。获取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}}

【问题讨论】:

  • 虽然您不需要像维基百科中使用的标签那样复杂的东西,但您也可以查看MediaWiki Parser.php 源代码。
  • @Tigger 好点,我不知道它遵循 wiki 标签语法

标签: php regex preg-match-all


【解决方案1】:

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

$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 demo


与你所拥有的相比:

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

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

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

对于可选属性,您有[\{]{0,1}([\w\W\s]*?)\}{0},这是使每个部分都可选的有效尝试。相反,我使用(?&gt; group )?(参见non-capturing groupsatomic groups)来使整个子模式可选(使用?quantifier)。

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

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

您使用[\w\s]+ 匹配文本,该文本匹配单词字符和空格,但无法匹配标点符号和其他字符。我本可以使用.*?,它也可以正常工作。但是,我使用了以下构造,它匹配相同,但性能更好:

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

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

\{/\1}

假设:

  • 属性在引号中没有右大括号,例如 "te}xt",这可能会导致其中断。

【讨论】:

  • 马里亚诺你碰巧拯救了我的一天!相信我,你救了我。正则表达式是我在处理项目时总是偶然发现的一件事。我不能只是帮助它每次给我带来的挫败感。再次感谢。
  • 请您修改您的解决方案以包括捕获结束 {/COMMAND_NAME} 标记。原因是因为某些命令可能是内联的,例如 {MODL{name=module_name,title=title of the module,access=access_rule}} 这是一个模块替换。与 ACCESS 不同,它依赖于中间的文本。再次感谢。
  • 很高兴它对您有所帮助。我认为没有理由捕获结束标签,因为如果你有一个匹配文本(第 2 组)
  • 好的。但我需要结束标记组,即 {/COMMAD_NAME} 存在。意味着它是可选的。有些命令是内联的。因此,块命令替换将发生在中间的文本上,而内联标记只会替换 COMMAND 声明。希望你理解
  • 我仍然认为您不需要它,但是我已经在您发表评论之前编辑了代码。享受:)
猜你喜欢
  • 1970-01-01
  • 2012-04-01
  • 2021-04-14
  • 2013-04-08
  • 2016-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-02
相关资源
最近更新 更多