【问题标题】:Recursive Regex to match smarty if else statements递归正则表达式以匹配 smarty if else 语句
【发布时间】:2013-12-10 09:31:34
【问题描述】:

我想匹配 smarty 模板中的 if else 语句。并在那里插入我自己的标签。在我的示例中,<OPEN></CLOSE>

这是我的代码:

$value =
<<<SMARTY
{if}
    text1
    {if}
        text2
    {/if}
    text3
{/if}


{if}
    text1
{else}
    text2
{/if}


{if}
    text1
    {if}
        text2
    {else}
        text3
    {/if}
    text
{/if}
SMARTY;

echo filter($value);
function filter($value)
{
    $pattern =
        '(\{(?:if|else).*?\})'.  // open
        '((?:'.

        '[^{]'.
        '|\{(?!/?if|else)'.
        '|(?R)'.

        ')+)'.
        '(\{(?:\/if|else)\})';   // close

    return preg_replace_callback('#'.$pattern.'#', 'filter_callback', $value);
}
function filter_callback($matches)
{
    $m2 = $matches;
    $m2[0] = preg_replace(array('/[\n\r]/','/ +/','/^ /'),array('',' ',''), $m2[0]);
    $m2[2] = preg_replace(array('/[\n\r]/','/ +/','/^ /'),array('',' ',''), $m2[2]);
    print_r($m2);

    return $matches[1].'<OPEN>'.filter($matches[2]).'</CLOSE>'.$matches[3];
}

但它不能正常工作。

例如我想有以下输出:

{if}<OPEN>
    text1
</CLOSE>{else}<OPEN>
    text2
</CLOSE>{/if}

{if}<OPEN>
    text1
    {if}<OPEN>
        text2
    </CLOSE>{else}<OPEN>
        text3
    </CLOSE>{/if}
    text
</CLOSE>{/if}

如果有人有想法?

【问题讨论】:

  • 正则表达式本质上不是递归的,不能很好地处理递归匹配。为什么可以在这个答案中找到解释(HTML 也是一种递归语言,因此适用相同的原则):stackoverflow.com/a/1758162/334053 您只需为 Smarty 编写(或查找)一个解析器并做您想做的事情用 PHP 做。
  • @SpikeX 用于我在表达式中使用 (?R) (us2.php.net/manual/de/regexp.reference.recursive.php) 的递归

标签: php regex recursion smarty


【解决方案1】:

此任务不需要递归正则表达式。 PHP 中递归正则表达式的问题在于您无法轻松访问不同递归级别的捕获。对于替换任务,您可以忘记它。

另一种解决方案:

$searches = array('{if}', '{else}', '{/if}');
$reps = array('{if}<OPEN>', '</CLOSE>{else}<OPEN>', '</CLOSE>{/if}');

$result = str_replace($searches, $reps, $value); // probably the faster way

$patterns = array('~{if}~', '~{else}~', '~{/if}~');
$reps = array('$0<OPEN>', '</CLOSE>$0<OPEN>', '</CLOSE>$0');

$result = preg_replace($patterns, $reps, $value);

print_r($result);

注意:您可以使用以下方法避免一次通过:

$patterns = array('~(?<={if}|{else})~', '~(?={(?:/if|else)})~');
$reps = array('<OPEN>', '<CLOSE>');

编辑:如果你想提取参数并将它们作为一种标签属性重用,你可以使用 preg_replace 方式(无需使用 preg_replace_callback):

$patterns = array('~{if(?:( )[^(}]+\(([^)]+)\))?}~', '~{else}~', '~{/if}~');
$reps = array('$0<OPEN$1$2>', '<CLOSE>$0<OPEN>', '<CLOSE>$0');

$result = preg_replace($patterns, $reps, $value);

注意:描述参数的子模式[^)]+ 可以替换为
(?s)(?&gt;[^)\']++|\'(?&gt;[^\'\\]++|\\{2}|\\.)*\')+ 以允许在带有单引号的参数内使用右括号。

【讨论】:

  • 在下一步中,我想找到特殊的“if else 语句”,例如 {if mystatement param1 param2}{if}{else}{/if}{/if} 并获取参数。您的解决方案找不到特殊语句。
  • @laemmi_punk:您可以通过对模式稍作修改来调整第二种解决方案,并使用preg_replace_callback 来获取您想要的内容。如果您需要更多帮助,请在您的问题中提供具体示例。
【解决方案2】:

这是匹配特殊 if 语句的具体示例:

$value =
<<<SMARTY
{if}
    text1
    {if \$user->isAllowed(null,'favourites','read')}
        text2
    {/if}
    text3
{/if}


{if \$user->isAllowed(null,'favourites','read')}
    text1
{else}
    text2
{/if}


{if \$user->isAllowed(null,'favourites','read')}
    text1
    {if}
        text2
    {else}
        text3
    {/if}
    text
{/if}
SMARTY;

echo filter($value);
function filter($value)
{
    $pattern =
        '(\{(?:if|else).*?\})'.  // open
        '((?:'.

        '[^{]'.
        '|\{(?!/?if|else)'.
        '|(?R)'.

        ')+)'.
        '(\{(?:\/if|else)\})';   // close

    return preg_replace_callback('#'.$pattern.'#', 'filter_callback', $value);
}
function filter_callback($matches)
{
    if(preg_match('#\{if.*?\$user\-\>isAllowed\((.*?)\)[^\}]*?\}#', $matches[1], $params)) {
        return $matches[1].'<OPEN '.$params[1].'>'.filter($matches[2]).'</CLOSE>'.$matches[3];
    }

    return $matches[1].filter($matches[2]).$matches[3];
}

【讨论】:

    猜你喜欢
    • 2020-08-26
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-30
    • 2019-10-30
    相关资源
    最近更新 更多