我在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}% -->) -->
模式有时会弄乱每个变量的开始和结束标记。
如何修复正则表达式以防止这种情况?
谢谢。
答案 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 +)从右到左搜索语法中的开始标记<!-- %{
,然后搜索下一个结束标记的第一个匹配项,然后首先替换该块,最终将首先替换最内层嵌套的变量。这应该可以解决您的问题。
您也可以反过来找到第一次出现的结束标记,然后向后查找相应的开始标记。