2010-06-23 60 views
0

我已经在PHP中创建了一个简单的模板“引擎”来将PHP生成的数据替换为HTML页面。下面是它如何工作的:PHP - 我需要一些帮助我的正则表达式

我主要的模板文件,我有变量,像这样:

<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}% -->) --> 

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

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

谢谢。

回答

4

答案是你不要这样做与正则表达式。正则表达式是一种常规语言。当你开始嵌套时,它不再是普通的语言。它至少是一种上下文无关的语言(“CFL”)。 CFLs只能被处理(假设他们毫不含糊)。

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

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

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

我的建议是不要写你自己的模板语言。那已经完成了。多次。使用Smarty或Zend,Kohana或其他软件。如果你真的写自己的话,那就正确地做。解析它。

+0

我对正则表达式并不是很满意,所以如果你能推荐一个替代方案,那么我就是全力以赴。我还能如何完成我在做的事情? – dave 2010-06-23 01:30:29

0

如果你问我认为你在问什么,那实际上是不可能的。如果我正确地阅读你的问题,你想匹配任意嵌套的<!-- ... -->序列与内部的特定事物。不幸的是,正则表达式只能匹配特定类型的字符串;任何正则表达式只能匹配regular language。一个知名的语言是而非经常是language of balanced parentheses (also known as the the Dyck language),这正是你想要匹配的。为了匹配任意嵌套的注释字符串,您需要一个更强大的工具。我相当确定有预先存在的PHP模板引擎;你可以看看其中的一个。

+0

用单个语句做这件事可能是不可能的(虽然我不是100%确定我买了那个),但它当然可以递归地或迭代地完成。当涉及PHP(或支持它们的任何语言)时,正则表达式变得比它们孤立的功能强大得多。 – Andrew 2010-06-23 01:58:29

0

要解决你的问题,你应该

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

我在过去做过类似的事情,而且我遇到过相同的嵌套问题。在你的情况下,我会做的是重复搜索你的文本的匹配(而不是搜索一次,并循环通过匹配),并提取所需的字符串搜索任何不包括您的关闭字符串。

在你的情况下,它可能会是这样的:

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

的正则表达式像这样的一场噩梦来解释,但基本上,([^(-->)]*)会发现,不包括您的结束标记任何字符串(姑且称之为即AAA)。它将位于匹配组中,该组本身就是您的模板标签,(<!--AAA-->)

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

我现在所做的大多数正则表达式都是用JavaScript编写的,所以我可能会错过一些PHP通过Perl获得的真棒细微差别。如果有人能够更清楚地写出这些,我会很高兴。

1

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

0

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

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

您也可以以相反的方式进行操作,找到第一个出现的结束标记,然后向后找到相应的开始标记。