PHP - 我的正则表达式需要一些帮助

时间:2010-06-23 01:23:15

标签: php regex

我在PHP中创建了一个简单的模板“引擎”,用于将PHP生成的数据替换为HTML页面。以下是它的工作原理:

在我的主模板文件中,我有这样的变量:

<title><!-- %{title}% --></title>

然后我将数据分配给主页加载的那些变量

$assign = array (
  'title' => 'my website - '
);

然后,我为内容页面加载了单独的模板块。上面真的只是处理页眉和页脚。在其中一个“内容模板文件”中,我有如下变量:

<!-- %{title=content page}% -->

执行此操作后,将对主模板数据进行编辑,以包含内容页面变量,从而产生:

<title>my website - content page</title>

使用以下代码执行此操作:

if (preg_match('/<!-- %{title=\s*(.*?)}% -->/s', $string, $matches)) {
   // Find variable names in the form of %{varName=new data to append}%
   // If found, append that new data to the exisiting data
   $string       = preg_replace('/<!-- %{title=\s*(.*?)}% -->/s', null, $string);
   $varData[$i] .= $matches[1];
}

这基本上删除了模板变量,然后将变量数据分配给现有变量。现在,一切正常。我遇到的问题是嵌套模板变量。如果我这样做:

<!-- %{title=content page (author: <!-- %{name}% -->) -->

模式有时会弄乱每个变量的开始和结束标记。

如何修复正则表达式以防止这种情况?

谢谢。

6 个答案:

答案 0 :(得分:4)

答案是你不要用正则表达式做这件事。正则表达式是常规语言。当你开始嵌套时,它不再是常规语言。它至少是一种无上下文的语言(“CFL”)。 CFL只能用堆栈处理(假设它们是明确的)。

具体而言,常规语言可以用有限状态机(“FSM”)表示。 CFL需要一个下推自动机(“PDA”)。

区别的一个例子是HTML中的嵌套标签:

<div>
  <div>inner</div>
</div>

我的建议是不要编写自己的模板语言。那已经完成了。多次。在Zend,Kohana或其他任何地方使用Smarty或其他东西。如果您自己编写,请正确执行。解析它。

答案 1 :(得分:1)

为什么要推出自己的模板引擎?如果你想要这种复杂性,那么很多地方已经为它提出了解决方案。你应该插入Smarty或类似的东西。

答案 2 :(得分:0)

如果你问我认为你在问什么,那根本不可能。如果我正确地阅读了您的问题,您希望将任意嵌套的<!-- ... -->序列与内部的特定内容进行匹配。不幸的是,正则表达式只能匹配某些类的字符串;任何正则表达式只能匹配regular language。一个众所周知的语言 not 是常规的language of balanced parentheses (also known as the the Dyck language),这正是你想要匹配的。为了匹配任意嵌套的注释字符串,您需要一个更强大的工具。我很确定有预先存在的PHP模板引擎;你可能会考虑其中一个。

答案 3 :(得分:0)

要解决您的问题,您应该

  • preg_match()替换为preg_match_all();
  • 找到模式,并将它们从最后一个替换为第一个;
  • 使用限制性更强的模式,例如'/<!-- %{title=\s*([^}]*?)}% -->/s'

答案 4 :(得分:0)

我过去做过类似的事情,但我遇到过与你相同的嵌套问题。在你的情况下,我会做的是重复搜索你的文本匹配(而不是搜索一次并循环匹配)并通过搜索任何不包括你的结束字符串的东西提取你想要的字符串。

在你的情况下,它可能看起来像这样:

/(<!--([^(-->)]*?)-->)/

像这样的正则数据集是一个噩梦来解释,但基本上,([^(-->)]*)会找到任何不包含结束标记的字符串(让我们称之为AAA)。它将位于匹配的组中,该组本身就是您的模板标记(<!--AAA-->)

我确信这种模板法是做错事的方法,但我从来都不知道做得更好。在ASP和ColdFusion中,你总是困扰我,你必须在HTML中嵌入你的脚本标签,当我开始自己做,我认为这是个人的失败。

我现在使用的大部分正则表都是使用JavaScript,所以我可能会错过PHP通过Perl的一些令人敬畏的细微差别。如果有人能够更清楚地写出来,我会很高兴。

答案 5 :(得分:0)

我过去也遇到过这个问题,虽然我没有使用正则表达式。

如果您使用strrpos(PHP5 +)从右到左搜索语法中的开始标记<!-- %{,然后搜索下一个结束标记的第一个匹配项,然后首先替换该块,最终将首先替换最内层嵌套的变量。这应该可以解决您的问题。

您也可以反过来找到第一次出现的结束标记,然后向后查找相应的开始标记。