Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 5 of 5
  1. #1
    Regular Coder thesmart1's Avatar
    Join Date
    Dec 2005
    Posts
    369
    Thanks
    7
    Thanked 3 Times in 3 Posts

    Conditionals in a Template - Regex

    I'm working on a template parser. I have variables done, but conditionals (if, elseif, else) are confusing me. I'm using preg_replace to parse everything, but I'm not very good with regex. I got if's to work with this:
    PHP Code:
    preg_replace(array('/\{L_(\w+)\}/e''/(<!-- IF C_([\w]+) -->)(.*)(<!-- ENDIF -->)/se'), array('$this->variables["$1"]''(($this->conditionals["$2"])?trim("$3", "\n"):"")'), $file_contents); 
    But now I'm trying to add else (and eventually I'll add elseif). I have this line to try to do that:
    PHP Code:
    preg_replace(array('/\{L_(\w+)\}/e''/(<!-- IF C_([\w]+) -->)(.*)([^<!-- ELSE -->.*])(<!-- ENDIF -->)/se'), array('$this->variables["$1"]''(($this->conditionals["$2"])?trim("$3", "\n"):trim("$3", "\n"))'), $file_contents); 
    The entire conditional code in the template (between "<!-- IF C_conditional_name -->" and "<!-- ENDIF -->") is put in $3 because of the "(.*)", and I don't know how to make that exclude "<!-- ELSE -->". Also, my regex to parse an optional "<!-- ELSE -->" is probably wrong. So can anyone help me exclude "<!-- ELSE -->" from the first "(.*)"?

    And some background info on this code: It is a class, and $this->variables is an associative array of {L_xx} var names and values and $this->conditionals is an associative array of conditional value names and values (i.e., if $this->conditionals['sample'] is true, so is C_sample in the template).

  • #2
    Regular Coder
    Join Date
    Jun 2004
    Posts
    565
    Thanks
    0
    Thanked 18 Times in 18 Posts
    Do a non-greedy match with .*? in your regex.

    dumpfi
    "Failure is not an option. It comes bundled with the software."
    ....../)/)..(\__/).(\(\................../)_/)......
    .....(-.-).(='.'=).(-.-)................(o.O)...../<)
    ....(.).(.)("}_("}(.)(.)...............(.)_(.))Ż/.
    ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
    Little did the bunnies suspect that one of them was a psychotic mass murderer with a 6 ft. axe.

  • #3
    Regular Coder thesmart1's Avatar
    Join Date
    Dec 2005
    Posts
    369
    Thanks
    7
    Thanked 3 Times in 3 Posts
    I have '/(<!-- IF C_([\w]+) -->)(.*?)([^<!-- ELSE -->.*])(<!-- ENDIF -->)/Use' as my regex for conditionals now, and I tried .*? and the U modifier by themselves and together. With this in my template file:
    Code:
    <!-- IF C_LOGGEDIN -->
    <p>Welcome back!</p>
    <!-- ELSE -->
    <p>Please log in</p>
    <!-- ENDIF -->
    I get this as output in my third match:
    Code:
    <p>Welcome back!</p>
    <!-- ELSE -->
    <p>Please log in</p>
    So either my regex is wrong (highly likely) or that didn't help (which I guess it should have..).

  • #4
    Regular Coder thesmart1's Avatar
    Join Date
    Dec 2005
    Posts
    369
    Thanks
    7
    Thanked 3 Times in 3 Posts
    OK, I rewrote my code a bit to parse out variables first, then find anything between "<!-- IF -->" and "<!-- ENDIF -->", and finally try to parse "<!-- ELSEIF -->"'s and an "<!-- ELSE -->" with a preg_replace_callback.

    PHP Code:
        function parseTemplate() {
            
    $file_contents $this->loadTemplate();
            
    //'(($this->conditionals["$2"])?trim("$3", "\n"):trim("$3", "\n"))'), 
            
    $temp preg_replace('/\{L_(\w+)\}/e''$this->variables["$1"]'$file_contents);
            return 
    preg_replace_callback('/(<!-- IF C_([\w]+) -->)(.*)(<!-- ENDIF -->)/s', array($this"parseConditionals"), $temp);
        }
        function 
    parseConditionals($matches) {
            
    var_dump($matches);
            
    preg_match_all('/(<!-- ELSE([\w]*) -->)(.*)/s'$matches[3], $matches2);
            echo 
    "\n\n";
            
    var_dump($matches2);
        } 
    I used ELSE([\w]*) to let the function match ELSEIF's and ELSE's and put the details of the conditional in the matches array. Right now I'm just printing all the matches it can find; I'll finish this to work with the matches later.

    And with that, I get:
    Code:
    array(5) {
      [0]=>
      string(125) "<!-- IF C_LOGGEDIN -->
    <p>Welcome back!</p>
    <!-- ELSEIF -->
    <p>Eh, wha?</p>
    <!-- ELSE --> <p>Please log in</p>
    <!-- ENDIF -->"
      [1]=>
      string(22) "<!-- IF C_LOGGEDIN -->"
      [2]=>
      string(8) "LOGGEDIN"
      [3]=>
      string(89) "
    <p>Welcome back!</p>
    <!-- ELSEIF -->
    <p>Eh, wha?</p>
    <!-- ELSE -->
    <p>Please log in</p>
    "
      [4]=>
      string(14) "<!-- ENDIF -->"
    }
    
    
    array(4) {
      [0]=>
      array(1) {
        [0]=>
        string(67) "<!-- ELSEIF -->
    <p>Eh, wha?</p>
    <!-- ELSE -->
    <p>Please log in</p>
    "
      }
      [1]=>
      array(1) {
        [0]=>
        string(15) "<!-- ELSEIF -->"
      }
      [2]=>
      array(1) {
        [0]=>
        string(2) "IF"
      }
      [3]=>
      array(1) {
        [0]=>
        string(52) "
    <p>Eh, wha?</p>
    <!-- ELSE -->
    <p>Please log in</p>
    "
      }
    }
    for this template:
    Code:
    <!-- IF C_LOGGEDIN -->
    <p>Welcome back!</p>
    <!-- ELSEIF -->
    <p>Eh, wha?</p>
    <!-- ELSE -->
    <p>Please log in</p>
    <!-- ENDIF -->
    So it's including the next match in each match it's parsing (in the preg_match_all). I tried a "?" and a "/U" modifier to make it ungreedy, but then I would get nothing matched for the "(.*)". Is there any other way to prevent this? Like using regex to get a string that doesn't include "<!-- ELSE" instead of "(.*)"?
    Last edited by thesmart1; 08-16-2008 at 07:15 PM.

  • #5
    Regular Coder thesmart1's Avatar
    Join Date
    Dec 2005
    Posts
    369
    Thanks
    7
    Thanked 3 Times in 3 Posts
    I have another idea that I think I'll try tomorrow, but I'm wondering now if I should replace template code with PHP code and use exec instead. That way I could cache templates like other template systems do, but it may open up a security issue of executing PHP code that's in the templates (if I don't trust the web designer to not write malicious PHP code ). The overhead in the way I'm doing it now *shouldn't* be that great, since it's only a couple regex function calls, but exec'ing cached PHP code would definitely be faster. Anyone else have any thoughts on which method I should use?


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •