以下是我想要在标记{{if}}
和{{\if}}
之间提取包含的字符串,我的意思是第一个和最后一个(内部的将由引擎重新检查):
正则表达式是:\{\{(if)\}\}(((?!\{\{\/?\1\}\})[\s\S])*(\{\{\1\}\}(?2)*\{\{\/\1\}\})*((?!\{\{\/?\1\}\})[\s\S])*)\{\{\/\1\}\}
编辑3:我删除了支持TAG而没有结束TAG的义务。我重新格式化了未来用户的问题,了解下面的一些评论,请参阅帖子的第一个版本
更多,我有三个同时适用于我的三个比赛,这在网站regex101上没有效果。在比赛中必须支持换行符。虽然,我可以接受只有最后两个组合会给出两个匹配,因为我可以为if
更改单独iif
的标记。
我的另一个解决方案是不使用正则表达式,但如果可能,我想这样做。
答案 0 :(得分:3)
您可以使用
~{{ # Opening tag start
(\w+) # (Group 1) Tag name
\^ # Aux delimiter
([^^\{\}]?) # (Group 2) Specific delimiter
\^ # Aux delimiter
([^\{\}]+) # (Group 3) Parameters
}} # Opening tag end
( # (Group 4)
(?>
(?R) # Repeat the whole pattern
| # or match all that is not the opening/closing tag
[^{]*(?:\{(?!{/?\1[^\{\}]*}})[^{]*)*
)* # Zero or more times
)
{{/\1}} # Closing tag
~ix
请参阅regex demo
通常,表达式基于递归和tempered greedy token。 [^{]*(?:\{(?!{/?\1[^\{\}]*}})[^{]*)*
部分是展开的(?s:(?!{{/?\1}}).)*
模式,匹配任何不是.
或{{TAG}}
字符序列起点的字符({{/TAG}}
)。< / p>
此模式不需要DOTALL修饰符,因为模式中没有.
。
这是PHP demo:
$re = '~{{(\w+)\^([^^\{\}]?)\^([^\{\}]+)}}((?>(?R)|[^{]*(?:\{(?!{/?\1[^\{\}]*}})[^{]*)*)*){{/\1}}~i';
$str = "before {{if^^p1^p2}} IN1; {{if^ ^p1}} {{iif}} IN3 {{/if}} IN1-1 {{/if}} after\nbefore {{if^ ^p1}} IN1; {{if^ ^p1}} {{if^ ^p1}} IN3 {{/if}} {{/if}} IN1-1 {{/if}} after\nbefore {{if^ ^p1}} IN1; {{if^ ^p1}} {{if^ ^p1}} IN3 {{/if}} {{/if}} IN1-1 {{if^ ^p1}} IN4 {{/if}} {{/if}} after";
preg_match_all($re, $str, $matches);
print_r($matches);