正则表达式匹配嵌套的开始和结束标签
Regex matching nested beginning and ending tags
这里是我想提取标签 {{if}}
和 {{\if}}
之间包含的字符串,我的意思是第一个和最后一个(引擎将重新检查内部的):
- "before {{if^^p1^p2}} IN1; {{if^ ^p1}} {{iif}} IN3 {{/if}} IN1-1 {{/if}} after"
- "before {{if^ ^p1}} IN1; {{if^ ^p1}} {{if^ ^p1}} IN3 {{/if}} {{/if}} IN1-1 {{/if}} after"
- "before {{if^ ^p1}} IN1; {{if^ ^p1}} {{if^ ^p1}} IN3 {{/if}} {{/if}} IN1-1 {{if^ ^p1}} IN4 {{/if}} {{/if}} after"
正则表达式是:\{\{(if)\}\}(((?!\{\{\/?\}\})[\s\S])*(\{\{\}\}(?2)*\{\{\/\}\})*((?!\{\{\/?\}\})[\s\S])*)\{\{\/\}\}
编辑 3:我删除了支持标签的义务,但没有结束标签。我为未来的用户重新格式化了问题,为了理解下面的一些评论,请参阅 post
的第一个版本
更多,我让它同时适用于所有三个,给我三个匹配,这在网站 regex101 上不起作用。比赛中必须支持换行符。虽然,我可以接受只有最后两个组合给出两个匹配项,因为我可以将单独的 if
的标签更改为 iif
.
我的另一个解决方案是不使用正则表达式,但如果可能的话我想这样做。
您可以使用
~{{ # 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
[^{]*(?:\{(?!{/?[^\{\}]*}})[^{]*)*
)* # Zero or more times
)
{{/}} # Closing tag
~ix
一般来说,表达式是基于递归和一个tempered greedy token。 [^{]*(?:\{(?!{/?[^\{\}]*}})[^{]*)*
部分是展开的 (?s:(?!{{/?}}).)*
模式,匹配任何不是 {{TAG}}
或 {{/TAG}}
字符序列起点的字符 (.
)。
此模式不需要 DOTALL 修饰符,因为模式中没有 .
。
这是一个PHP demo:
$re = '~{{(\w+)\^([^^\{\}]?)\^([^\{\}]+)}}((?>(?R)|[^{]*(?:\{(?!{/?[^\{\}]*}})[^{]*)*)*){{/}}~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);
这里是我想提取标签 {{if}}
和 {{\if}}
之间包含的字符串,我的意思是第一个和最后一个(引擎将重新检查内部的):
- "before {{if^^p1^p2}} IN1; {{if^ ^p1}} {{iif}} IN3 {{/if}} IN1-1 {{/if}} after"
- "before {{if^ ^p1}} IN1; {{if^ ^p1}} {{if^ ^p1}} IN3 {{/if}} {{/if}} IN1-1 {{/if}} after"
- "before {{if^ ^p1}} IN1; {{if^ ^p1}} {{if^ ^p1}} IN3 {{/if}} {{/if}} IN1-1 {{if^ ^p1}} IN4 {{/if}} {{/if}} after"
正则表达式是:\{\{(if)\}\}(((?!\{\{\/?\}\})[\s\S])*(\{\{\}\}(?2)*\{\{\/\}\})*((?!\{\{\/?\}\})[\s\S])*)\{\{\/\}\}
编辑 3:我删除了支持标签的义务,但没有结束标签。我为未来的用户重新格式化了问题,为了理解下面的一些评论,请参阅 post
的第一个版本更多,我让它同时适用于所有三个,给我三个匹配,这在网站 regex101 上不起作用。比赛中必须支持换行符。虽然,我可以接受只有最后两个组合给出两个匹配项,因为我可以将单独的 if
的标签更改为 iif
.
我的另一个解决方案是不使用正则表达式,但如果可能的话我想这样做。
您可以使用
~{{ # 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
[^{]*(?:\{(?!{/?[^\{\}]*}})[^{]*)*
)* # Zero or more times
)
{{/}} # Closing tag
~ix
一般来说,表达式是基于递归和一个tempered greedy token。 [^{]*(?:\{(?!{/?[^\{\}]*}})[^{]*)*
部分是展开的 (?s:(?!{{/?}}).)*
模式,匹配任何不是 {{TAG}}
或 {{/TAG}}
字符序列起点的字符 (.
)。
此模式不需要 DOTALL 修饰符,因为模式中没有 .
。
这是一个PHP demo:
$re = '~{{(\w+)\^([^^\{\}]?)\^([^\{\}]+)}}((?>(?R)|[^{]*(?:\{(?!{/?[^\{\}]*}})[^{]*)*)*){{/}}~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);