使用正则表达式来匹配?但不是\?

时间:2010-04-15 01:12:18

标签: php regex preg-match pcre

我有一个PHP正则表达式,它可以很好地解析一些奇怪的遗留客户端模板,直到最近我们发现模板表达式中包含一个转义的问号(\?)。我的常规表达能力不足以将我的软弱面条包裹在一个负向的前方或者一些技术 - 笨蛋 - 所以,正确的方向的提示或点将非常感激。

我的PHP:

preg_match_all("/\{\{IF (.*)\?(.*):(.*)\}\}/U", $template, $m, PREG_SET_ORDER);

好的,当我发布这个问题时,我有点不知所措。请允许我将其置于适当的背景下。

模板代码如下所示:

{{IF VAR?"SHOW: THIS?":"SHOW {{ELSE}}"}}

哪个应解析为:

if ($template[$var]) {
 echo "SHOW: THIS?";
} else {
 echo "SHOW ".$template['ELSE'];
}

我目前几乎用我的功能实现这一点,但并非完全如此。这是功能:

preg_match_all("/\{\{IF ((?:[^\\?]|\\.)*)\?((?:[^\\:]|\\.)*):(.*)\}\}[^<\/]/", $template, $m, PREG_SET_ORDER);
if (count($m)) {
 foreach ($m as $o) {
  if (preg_match("/(.*)\s+(==|!=)\s+(.*)/", $o[1], $x)) {
   if (preg_match("/^\"(.*)\"/", $x[1], $cx)) $e1 = $cx[1];
   else $e1 = is_numeric($x[1])?$x[1]:$data[$x[1]];
   if (preg_match("/^\"(.*)\"/", $x[3], $cx)) $e2 = $cx[1];
   else $e2 = is_numeric($x[3])?$x[3]:$data[$x[3]];
   if (preg_match("/^\"(.*)\"/", $o[2], $ox)) $er[0] = $ox[1];
   else $er[0] =  addslashes(htmlspecialchars($data[$o[2]]));
   if (preg_match("/^\"(.*)\"/", $o[3], $ox)) $er[1] = $ox[1];
   else $er[1] = addslashes(htmlspecialchars($data[$o[3]]));
   $eval = "\$od = (\"$e1\" $x[2] \"$e2\")?\"$er[0]\":\"$er[1]\";";
   eval($eval);
  } else {
   $od = $data[$o[1]]?$o[2]:$o[3];
   if (preg_match("/^\"(.*)\"/", $od, $x)) $od = $x[1];
   else $od = $data[$od];
  }
  $template = str_replace($o[0], $od, $template);
 }
}

if (is_array($data))
 foreach ($data as $k => $v) $template = str_replace('{{'.$k.'}}', $v, $template);
return $template;

3 个答案:

答案 0 :(得分:2)

您需要更改(.*)区域 - 您不希望匹配任何内容的序列。相反,您希望匹配一系列非转义字符或转义序列:((?:[^\\]|\\.)*)这将匹配包含反斜杠转义的任何字符串。我认为你可以通过指定你不想匹配你不能匹配的问号或冒号来提高性能;如果你这样做,你最终会得到正则表达式/\{\{IF ((?:[^\\?]|\\.)*)\?((?:[^\\:]|\\.)*):(.*)\}\}/。虽然这看起来很讨厌,但我只是用你上面的结构替换你的(.*);这很简单。

答案 1 :(得分:1)

为什么不

(.*)[^\\]\?(.*)

答案 2 :(得分:1)

这是有效的。感谢@absz指出正确的方向。

preg_match_all("/\{\{IF ([^\"\\]]*(\\.[^\"\\]]*)*)\?((?:[^\\:]|\\.)*):(.*)}\}/", $template, $m, PREG_SET_ORDER);