0

Basically I'm writing a small template parser that uses regex to parse some tags, at the moment I'm having trouble with matching multiple tags in the same file.

Here is my current regex pattern:

$regex = '#\{if \$([A-Za-z0-9_]+)\}([^{]+)(\{else\})?([^{]+)?\{\/if\}#'

Am I missing something here?

Here an example of a template file I'm trying to parse

{if $name}
   Hi my name is: {$name}.
{else}
   No name set.
{/if}

{if $male}
   Gender: Male.
{else}
   Gender: Female.
{/if}

Here is my php code as it stands at the moment:

<?php
$tpl_file = file_get_contents('template.tpl');
$regex = '#\{if \$([A-Za-z0-9_]+)\}([^{]+)(\{else\})?([^{]+)?\{\/if\}#';

if (preg_match_all($regex, $tpl_file, $matches)) {
   print_r($matches);
}
?>

Any help is greatly appreciated. Cheers

  • `(\{else\})?([^{]+)?` <-- this doesn't sound right: you want to make _the whole else block optional_, here you make either `else` optional or anything which is not a `{`. You want to put all of this in one same group, not two separate groups. – fge Jan 16 '12 at 19:39
  • Some more tips: You don't need to escape `/` if you already use another delimiter. And for testing you should play with `-` in place of escaped `\{` and `\}` and/or use the `/x` mode for readability in any case. – mario Jan 16 '12 at 19:44
  • The thing I noticed right off the bat, without seeing your PHP code is that with this bit: `([^{]+)` it won't match any lines with template variables, such as {$name} on line 2. Because of that, the regex you posted will only grab the second half of the template file example you used. Unfortunately, I can't offer any suggestions because I don't know what you want to do with the {$name} variable - or why you had code in there that would look for lines without variables only, so without more information, that's as best as I can do. – Francis Lewis Jan 16 '12 at 19:42
  • The {$name} tag is replaced by a different function using preg_replace() after I have parsed the if tags. – chtombleson Jan 16 '12 at 19:46
  • If that's the case, then if you allow code with curly braces, your regex will work. Is there any reason you're basically recreating what many have already created in template engines? There's a number of options out there, the most popular one that comes to mind is Smarty. – Francis Lewis Jan 16 '12 at 20:29
  • I could use smarty but I don't need all it's features. Just something small, easy to extend. – chtombleson Jan 16 '12 at 22:55

2 Answers2

1

You shouldn't make such a parser using regex. It's just not possible. Anyway, as Francis said, if you remove the {$name} from the first if block, it will match using your existing code.

Community
  • 1
  • 1
cambraca
  • 27,014
  • 16
  • 68
  • 99
1

Regex is tragically, tragically poor at dealing with matching nested closures. Anything with start and end structures are closures and stuffing them inside each other or dealing with them on meta-levels is super hard.

See the top answer to this post more specifically about (X)HTML RegEx match open tags except XHTML self-contained tags and then consider that you've basically reinvented a procedure-XML-like syntax with different braces.

Regex is for "regular expression" matching. Unfortunately for you, "regular" doesn't mean what it regularly means but is instead a mathematical catchphrase for a particular type of problem.

Community
  • 1
  • 1
Mark
  • 1,058
  • 6
  • 13