首先正如蒂姆正确指出的那样 - 用正则表达式解析 HTML 是不明智的。
第二:如前所述,问题中的正则表达式是不可读的。我冒昧地重新格式化它。这是一个工作脚本,其中包含完全相同的正则表达式的注释可读版本:
<?php // test.php Rev:20120830_1300
$re = '%
# Match a non-nested "{block:name:func(params)}...{/block:name}" structure.
(?P<opening> # $1: == $opening: BLOCK start tag.
{ # BLOCK tag opening literal "{"
(?P<inverse>[!])? # $2: == $inverse: Optional "!" negation.
block: # Opening BLOCK tag ident.
(?P<name>[a-z0-9\s_-]+) # $3: == $name: BLOCK element name.
( # $4: Optional BLOCK function.
: # Function name preceded with ":".
(?P<function>[a-z0-9\s_-]+) # $function: Function name.
( # $5: Optional function parameters.
[\s]? # Allow one whitespace before (params).
\( # Literal "(" params opening char.
(?P<params>[^)]*) # $6: == $params: function parameters.
\) # Literal ")" params closing char.
)? # End $5: Optional function parameters.
)? # End $4: Optional BLOCK function.
} # BLOCK tag closing literal "}"
) # End $1: == $opening: BLOCK start tag.
(?P<contents> # $contents: BLOCK element contents.
[^{]* # {normal) Zero or more non-"{"
(?: # Begin {(special normal*)*} construct.
\{ # {special} Allow a "{" but only if it is
(?!/?block:[a-z0-9\s_-]+\}) # not a BLOCK tag opening literal "{".
[^{]* # More {normal}
)* # Finish "Unrolling-the-Loop" (See: MRE3).
) # End $contents: BLOCK element contents.
(?P<closing> # $closing: BLOCK element end tag.
{ # BLOCK tag opening literal "{"
/block: # Closing BLOCK tag ident.
(?P=name) # Close name must match open name.
} # BLOCK tag closing literal "}"
) # End $closing: BLOCK element end tag.
%six';
$text = file_get_contents('testdata.html');
if (preg_match($re, $text, $matches)) print_r($matches);
else echo("no match!");
?>
请注意,额外的缩进和注释允许人们真正理解正则表达式试图做什么。我的测试表明正则表达式没有任何问题,并且它可以像宣传的那样工作。它甚至实现了 Jeffrey Friedl 先进的“Unrolling-the-Loop”效率技术,所以写这篇文章的人有一些真正的正则表达式技巧。
例如,鉴于以下数据取自原始问题:
<ul>{block:menu}
<li><a href="{var:link}">{var:title}</a>
{/block:menu}</ul>
这是脚本的(正确)输出:
'''
Array
(
[0] => {block:menu}
<li><a href="{var:link}">{var:title}</a>
{/block:menu}
[opening] => {block:menu}
[1] => {block:menu}
[inverse] =>
[2] =>
[name] => menu
[3] => menu
[4] =>
[function] =>
[5] =>
[6] =>
[params] =>
[7] =>
[contents] =>
<li><a href="{var:link}">{var:title}</a>
[8] =>
<li><a href="{var:link}">{var:title}</a>
[closing] => {/block:menu}
[9] => {/block:menu}
)
'''
当可选function
并且params
包含在测试数据中时,它也可以工作。
也就是说,我对问题/正则表达式有一些问题:
- 正则表达式混合命名和编号的捕获组。
{
and是元字符,}
应该转义(尽管 PCRE 能够正确确定在这种情况下它们应该按字面意思解释)。
- 目前尚不清楚用户将如何使用可选捕获的组。
- 目前尚不清楚 OP 使用此正则表达式有什么问题。