我不太确定标题是否解释了我的问题所以我去了。我试图在PHP中创建模板系统。语法如下所示:
#foreach(params):
<ul>
<li>Username: *{users_username}</li>
<li>ID: *{users_id}</li>
<li>Email: *{users_email}</li>
<li>Password: *{users_password}</li>
<li>Index: *{count}</li>
<li>Count: *{index}</li>
</ul>
#foreach(params):
<ul>
<li>Username: *{users_username}</li>
<li>ID: *{users_id}</li>
<li>Email: *{users_email}</li>
<li>Password: *{users_password}</li>
<li>Index: *{count}</li>
<li>Count: *{index}</li>
</ul>
#endforeach;
#endforeach;
我想首先匹配从... #blockname(parameters):
开始到#endblockname;
开头的最里面的块。正则表达式还应该捕获块的内容。我认为这可以通过在#blockname(parameters):
之后和#endblockname;
之前获取所有内容来实现,除非之前有另一个#blockname(parameters):
。
然后我会多次运行PHP preg_replace,每次都删除另一层块。
如果您有任何疑问,请随时提出。
编辑:到目前为止,我已经尝试了以下内容:@[a-z]{1,}\([^)]*\):((?:(?!@[a-z]{1,}\([^)]*\):).)*?)@end[a-z]{1,};
仅在没有换行符时才有效。
答案 0 :(得分:3)
以下正则表达式将按照您定义的语法匹配最内层的块:
/
^[ \t]*[#] # start of line and indent up to "#"
(?<blockname>\w+) # blockname (captured)
(?:[(](?<params>[^]]*)[)])?: # text inside brackets (captured)
[ \t]*\n # and optional space to end of line
(?<body>(?> # get the body (captured)
(?![ \t]*[#]\w) # if not followed by a block definition
.*\n # match the whole line
)*)
[ \t]*[#]end\g<blockname>; # until it matches "#end" + the text captured in blockname
/mx
它使用 named group 来捕获阻止名称
(?<blockname>\w+)
和另一个匹配来自块体的所有行,除非有一行以另一个块定义开头(使用 negative lookahead )。
(?<body>(?>
(?![ \t]*[#]\w)
.*\n
)*)
直到它可以匹配块的结尾,使用 backreference to (我们之前匹配的文本)命名组
[#]end\g<blockname>;
这会捕获blockname
,params
和body
中的文字,如果您将此正则表达式与preg_match_all()
或preg_replace_callback()
一起使用,您可以方便地获取匹配的文字为:
preg_match_all($re, $str, $matches);
$matches["blockname"][matchNum]
$matches["params"][matchNum]
$matches["body"][matchNum]