我正在尝试为if else语句创建一个bbcode。 这是模式:
\[if([^\b\[\]]+)\](?(?=[\[else\]])(.*?)(?:\[else\])(.*?)|(.*?))\[\/if\]
它应匹配以下字符串:
1: [if %platform.desktop%][icon name="check-square"][/icon][else][icon name="cancel-square"][/icon][/if]
2: [if %platform.desktop%][icon name="check-square"][/icon][/if]
结果应为:
匹配1:
1: " %platform.desktop%"
2: "[icon name="check-square"][/icon]"
3: "[icon name="cancel-square"][/icon]"
第2场比赛:
1: " %platform.desktop%"
2: "[icon name="check-square"][/icon]"
但由于某种原因,else语句没有得到任何结果。 没有匹配2 。
这应该适用于PHP。
答案 0 :(得分:2)
我建议你改变你的正则表达式。
\[if([^\[\]]+)\](?(?=.*\[else\])(.*?)(?:\[else\])(.*?)|(.*?))\[\/if\]
我在原始正则表达式中做了哪些更改?
\[if([^\[\]]+)\](?(?=[\[else\]])(.*?)(?:\[else\])(.*?)|(.*?))\[\/if\]
^ ^
删除上面提到的sqaure括号,这意味着一个字符类。因此[\[else\]]
匹配[
或e
或l
,...
然后在正向前方.*?
内添加(?=.*?\[else\])
以上正则表达式的作用是什么?
上面的正则表达式使用正则表达式if,else子句。即,如果条件为真,则匹配特定的特定字符块,如果条件为假,则匹配另一特定字符块。
请参阅上述链接右侧的正则表达式解释。
答案 1 :(得分:2)
当你想构建一个复杂的模式时,我建议你使用命名的子模式,使代码更清晰(并且更容易处理递归,这可能是你想要做的事情所需要的) :
$pattern = '~
(?(DEFINE)
(?<tag>\[(\w+)[^]]*]\g<content>\[/\g{-1}])
(?<text> [^[]+)
(?<condition> \[if ([^]]+)]\g<content>(?:\[else]\g<content>)?\[/if] )
(?<content> (?:\g<text>|\g<condition>|\g<tag>)*)
)
\[if[ ](?<cond>[^]]+)](?<true>\g<content>)(?:\[else](?<false>\g<content>))?\[/if]
~x';
$str = '1: [if %platform.desktop%][icon name="check-square"][/icon][else][icon name="cancel-square"][/icon][/if]
2: [if %platform.desktop%][icon name="check-square"][/icon][/if]';
if (preg_match_all($pattern, $str, $matches, PREG_SET_ORDER)) {
foreach ($matches as $m) {
echo $m['cond'] . ' : ' . $m['true'] . ' : ' . $m['false'] . "\n";
}
}
在上面的模式中,(?(DEFINE)...)
内的第一部分允许您定义所需的所有子模式而不匹配任何内容。
然后,您可以轻松编写主要模式:
\[if[ ](?<cond>[^]]+)](?<true>\g<content>)(?:\[else](?<false>\g<content>))?\[/if]
用于定义命名子模式的语法是(?<name>...)
。要使用子模式,只需编写:\g<name>