views:

100

answers:

3

I have a PHP regular expression that has been functioning fairly well to parse some odd legacy client templates until recently when we found an escaped question mark (\?) included in a template expression. I'm not strong enough with my regular expression-fu to wrap my feeble noodle around a negative look ahead or some techno-mumbo-jumbo so, tips or points in the right direction would be greatly appreciated.

My PHP:

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

Okay, I was a little overwhelmed when I posted this question. Allow me to put it into proper context.

Template code looks like this:

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

Which should be parsed as:

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

I am currently almost achieving this with my function, but not entirely. This is the function:

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;
+1  A: 

Why not

(.*)[^\\]\?(.*)
Chris
That wouldn't match a line beginning with a ? though. You'd have to add something else for that. Is that a case you need to handle as well?
Chris
+2  A: 
Antal S-Z
Gooder... warmer. I wish I articulated my question better the first time.
J.Milly
+1  A: 

Here's what worked. Thanks to @absz for a point in the right direction.

preg_match_all("/\{\{IF ([^\"\\]]*(\\.[^\"\\]]*)*)\?((?:[^\\:]|\\.)*):(.*)}\}/", $template, $m, PREG_SET_ORDER);
J.Milly
Glad I could help.
Antal S-Z