正则表达的粉丝,又来了。 上一次,Casimir和Hippolyte为我的问题找到了一个优雅的解决方案。
Regex: matching open/close tags which accepts another open/close tag with same name
自从他(她的?)正则表达式开始以来,程序发生了一些变化, 我可以设法找到一个有效的解决方案。 但是,我对它并不完全满意。
问题是现在有两种类型的组件:
但是,它们都有相同的结束标记。 此外,两种类型的组件都可以包含其他类型(加号可以包含减号,反之亦然)。
我只需要获取“plus components”的内容。
<?php
$subject = '
{{poo+}} # T1
Hello
{{poo-}} # T2
Nested 1
{{/poo}} # T3
{{/poo}} # T4
{{poo+}} # T5
Bye
{{/poo}} # T6
';
// The solution below works, but I'm forced to capture all types of components.
// I can differentiate them later using php...but I'm looking for a regex that does that immediately.
//
// The reason why is that in the real program, there are three components types, and the syntax is
// slightly more complex (so the regex would be slower to try all three types of components than just one),
// and there could be more component instances.
$p = '`(?x)
{{(\w+)([+-])}}
# ( # you need probably this capture group later
(?>
[^{]++
|
{ (?!{)
|
{{ (?! /? \1 \b) # if needed you can add }} in the lookahead
|
(?R)
)*
# )
{{/\1}}
`';
preg_replace_callback($p, function($match){
var_dump($match);
}, $subject);
答案 0 :(得分:1)
Bonjour ling,
这可能是本周最有趣的正则表达式问题之一。
我还没有研究过其他人的细节,所以从头开始这就是我的建议。
(?x)
(?>{{(?:[\w-]+(\+)?)}}
(?:
[^{}]++
|
((?>{{[\w+-]+}}(?:[^{}]++|(?>(?2)))+{{/[\w+-]+}}))
)++
{{/[\w+-]+}}
)
(?(1)|(*SKIP)(?!))
它是如何运作的?
密钥非常简单:我们将外部分隔符与{{(?:[\w-]+(\+)?)}}
匹配,可选择将+
中的poo+
捕获到第1组(如果有)。这允许我们最后在(?(1)|(*SKIP)(?!))
中检查我们在开始时是否有正确的分隔符(对第1组进行条件检查)。如果是,则在该阶段匹配成功。如果不是,我们跳过整个匹配,阻止引擎在嵌套集上尝试匹配。
其他详情:在分隔符之间,我们会多次匹配此表达式:
[^{}]++
|
((?>{{[\w+-]+}}(?:[^{}]+|(?2))+{{/[\w+-]+}}))
[^{}]++
允许我们匹配任何不是左右括号的内容。 (?2)
子程序调用引用自身。此行是一个递归蓝图,用于匹配嵌套在外部表达式中的大括号集。不相关的详细信息
当你说his (her?)
时,你的意思是h(?:is|er)
,对吗? :)
答案 1 :(得分:1)
你可以做些什么来确保你匹配poo +标签而不破坏递归调用的可能性,就是用一个测试是否达到递归级别的条件替换([+-])
。例如:
$p = '`(?x)
{{(\w+) (?(R)[+-]|\+) }}
# ( # you need probably this capture group later
(?>
[^{]++
|
{ (?!{)
|
{{ (?! /? \1 \b) # if needed you can add }} in the lookahead
|
(?R)
)*
# )
{{/\1}}
`';
这是一个简单的IF..THEN..ELSE:
(?(R) # IF the recursion level has been reached
[+-] # THEN matches any kind of tags
| \+ # ELSE matches only + tags
)