php 正则表达式抓取递归括号的内容

mbskvtky  于 2023-03-28  发布在  PHP
关注(0)|答案(2)|浏览(147)

我正在用PHP为我自己的个人项目编写一个模板编译器,遇到了一个问题,如果条件以)结尾,则@if指令无法正确获取指令的内容。

private function handleIf(string $page): string
{
    return preg_replace('/@if ?\( ?(.*?) ?\)(.*?)@endif/is', '<?php if ($1) { ?> $2 <?php } ?>', $page);
}
// the directive...
// @if(!empty($title))
// should result in
<?php !empty($title) { ?>
// but is instead rendered as
<?php !empty($title { ?>
// which obviously no worky

我该如何调整我的正则表达式来正确地匹配它?它必须是全局的和多行的,因为它是模板的一部分。我可以使用其他方法来提取指令吗?

raogr8fs

raogr8fs1#

对于给定的示例,您可以使用递归模式来匹配@if后面的平衡括号。
请注意,您正在将php代码与正则表达式进行匹配,这可能会给予意想不到的副作用。

@if\h*(\(((?:[^()]++|(?1))*)\))\s*(.*?)\s*@endif\b
  • @if\h*匹配@if,后跟可选空格
  • (捕获组1
  • \(匹配(
  • (捕获组2
  • (?:[^()]++|(?1))*重复匹配除()以外的任何字符,或重复第一个子模式
  • )关闭组2
  • \)匹配)
  • )关闭组1
  • \s*(.*?)\s*捕获组3,在可选的空白字符之间匹配尽可能少的任何字符
  • @endif\b匹配@endif后跟一个字边界

Regex demo|Php demo

$pattern = '/@if\h*(\(((?:[^()]++|(?1))*)\))\s*(.*?)\s*@endif\b/is';
$s = '@if(!empty($title)). test
and testing   @endif';
$subst = "<?php if($2) { ?>$3<?php } ?>";

$result = preg_replace($pattern, $subst, $s);

echo $result;

输出

<?php if(!empty($title)) { ?>. test
and testing<?php } ?>

如果您不想在中间交叉另一个@if(

@if\h*(\(((?:[^()]++|(?1))*)\))\s*((?:(?!@if\h*\().)*)\s*@endif\b

Regex demo

pqwbnv8z

pqwbnv8z2#

可以看到这个代码

/@if[ ]{0,}\((.*)\)(.*)@endif/gsU

输入文本

@if(!empty($title))
     <div>hello</div>
@endif

输出

<?php if ( !empty($title) ) { ?> 
     <div>hello</div>
 <?php } ?>

完整代码:

<?php //php 7.2.24

function handleIf(string $page): string
{
    return preg_replace('/@if[ ]{0,}\((.*)\)(.*)@endif/isU', '<?php if ( $1 ) { ?> $2 <?php } ?>', $page);
}

$title = "";

$code = '
@if(!empty($title))
     <div>hello</div>
@endif
';

echo handleIf($code);
?>

可以通过此链接https://rextester.com/DSN63422运行

相关问题