1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

How to go about this? REGEX & PHP

Discussion in 'PHP & Perl' started by altschule, Dec 6, 2010.

  1. altschule

    altschule Regular Member

    Joined:
    Sep 1, 2010
    Messages:
    282
    Likes Received:
    185
    Location:
    Sector 9
    I'm currently am on a personal project and am trying to build my own template engine, and am running into an issue that could easily be fixed with REGEX but I just can't figure it out.

    What I have at the moment is finding strings with
    Code:
    [somethinghere=this;somethingelse=that]
    , but I need to find the nests and handle them first, and just cannot figure it out. For example If it was
    Code:
    [somethinghere=this;somethingelse=[somethingcool||that];thenthis=thing]
    my desired REGEX would detect the brackets with nests, and then output the [somethingcool||that] for me.

    What I have now:
    Code:
    #\[(.*?)\]#
    What I tried, but didn't work:
    Code:
    #\[(.*?)\[(.*?)\](.*?)\]
     
  2. xrvel

    xrvel Registered Member

    Joined:
    Feb 4, 2009
    Messages:
    74
    Likes Received:
    15
    Gender:
    Male
    Home Page:
    Not the fanciest method but it works.

    PHP:
    <?php
    $s 
    '
    [somethinghere=this;somethingelse=[somethingcool||that];thenthis=thing]
    [somethinghere=this2;somethingelse=[somethingcool2||that2];thenthis=thing2]
    '
    ;
    function 
    x_parse($str) {
        
    $d = array();
        
    //if (preg_match_all('/\[((.*)\=(.*)\;?)\]/i', $str, $match)) {
        
    if (preg_match_all('/\[(.*)\]/i'$str$match)) {
            foreach (
    $match[1] as $n) {
                
    $new_d = array(
                    
    'full' => $n,
                    
    'within_brackets' => '',
                    
    'within_brackets_2' => '',
                    
    'exploded' => array()
                );
                if (
    preg_match('/\[(.*)\]/i'$n$match2)) {
                    
    $new_d['within_brackets'] = $match2[0];
                    
    $new_d['within_brackets_2'] = $match2[1];
                    
    $new_d['exploded'] = explode('||'$match2[1]);
                }
                
    $d[] = $new_d;
            }
        }
        return 
    $d;
    }
    echo 
    '<pre>';
    print_r(x_parse($s));
    echo 
    '</pre>';
    ?>
    Output :
    Code:
    Array
    (
        [0] => Array
            (
                [full] => somethinghere=this;somethingelse=[somethingcool||that];thenthis=thing
                [within_brackets] => [somethingcool||that]
                [within_brackets_2] => somethingcool||that
                [exploded] => Array
                    (
                        [0] => somethingcool
                        [1] => that
                    )
    
            )
    
        [1] => Array
            (
                [full] => somethinghere=this2;somethingelse=[somethingcool2||that2];thenthis=thing2
                [within_brackets] => [somethingcool2||that2]
                [within_brackets_2] => somethingcool2||that2
                [exploded] => Array
                    (
                        [0] => somethingcool2
                        [1] => that2
                    )
    
            )
    
    )
    
     
    • Thanks Thanks x 1
  3. altschule

    altschule Regular Member

    Joined:
    Sep 1, 2010
    Messages:
    282
    Likes Received:
    185
    Location:
    Sector 9
    I appreciate the code, but it still isn't accomplishing what I want it to, I know why, I just don't know how to fix it. I've actually been trying to find some "nested spinner" to refer to, but can't find anything. Because essentially, it's almost the same thing.

    I'm trying to take a string like this:
    Blah blah blah [var1=this;var2=that;var3=[subvar1=this;subvar2=that];var4=this] blah blah

    obviously the engine will have many of these in one file, I'm trying to find the first level, which in this case would be
    Code:
    [var1=this;var2=that;var3=[subvar1=this;subvar2=that];var4=this]
    but with this REGEX it will return this:
    Code:
    [var1=this;var2=that;var3=[subvar1=this;subvar2=that]
    I'm sure there would be a way to tell it to find the second instance of a "]" but then again, it wont always be nested like that... =/ confusing.
     
  4. risefromdeath

    risefromdeath Power Member

    Joined:
    Jul 1, 2009
    Messages:
    650
    Likes Received:
    107
    okay i am not clear what you are exactly trying to get..from what i get you are trying to match
    Code:
    [something[something]something]
    
    if thats it this should help
    PHP:
    preg_match_all('<\[.*?\[.*?\].*?\]>ims',$string,$result);
    modify according to your need
    Thanks
     
    • Thanks Thanks x 1
    Last edited: Dec 9, 2010
  5. risefromdeath

    risefromdeath Power Member

    Joined:
    Jul 1, 2009
    Messages:
    650
    Likes Received:
    107
    Please delete..double post
     
  6. MakeLemonade

    MakeLemonade Junior Member

    Joined:
    Mar 30, 2009
    Messages:
    148
    Likes Received:
    67
    Nesting is no problem with http://www.php.net/manual/en/function.preg-replace-callback.php. Make a recursive function.

    PHP:
    function match_brackets($matches) {
      if (!
    is_array($matches)) { 
       
    $matches = array($matches);
      foreach(
    $matches as $string) {
        if (
    preg_match('#match_brackets#'$string)) {
          
    preg_replace_callback('#match#','match_brackets',$string);
        }
        else {
          
    #code to do other stuff here - non bracket replacements
        
    }
      }
    }
    You could probably replace the foreach loop and just go by the number of expected match chunks you have. For example, if you're expecting 3 matches (before [], [], after[]) then you're only interested in doing recursion on the middle match ($matches[0]). You'd still have to do a test for count($matches) being 1 though.

    You WILL want to use a greedy match (.*) instead of non-greedy (.*?) so matches occur from the outside set of brackets in.

    I'm not providing the complete code, but I hope that gives you some ideas.
     
    • Thanks Thanks x 1
    Last edited: Dec 15, 2010
  7. altschule

    altschule Regular Member

    Joined:
    Sep 1, 2010
    Messages:
    282
    Likes Received:
    185
    Location:
    Sector 9
    Thanks, but I'm still running into issues. Basically what this is doing (well what I WANT it to do) is almost exactly what a nested spinner may do...
     
  8. easyroms

    easyroms Newbie

    Joined:
    Nov 5, 2009
    Messages:
    15
    Likes Received:
    1
    here you go.

    PHP:
    if(preg_match('/\[(?>[^\[\]]+|(?R))*\]/i',"[var1=this;var2=that;var3=[subvar1=this;subvar2=that];var4=this]",$matches))
    {
      
    var_dump($matches);
    }
     
  9. Micallef

    Micallef Supreme Member

    Joined:
    Apr 29, 2009
    Messages:
    1,345
    Likes Received:
    1,221
    Occupation:
    SE Manipulator
    Location:
    London, UK
    Home Page:
    I'm interested - what sort of a template engine are you building?
     
  10. Crazy

    Crazy Jr. Executive VIP

    Joined:
    Jun 13, 2009
    Messages:
    640
    Likes Received:
    319
    Occupation:
    VB, C#, XHTML, CSS, PHP, MySQL, JavaScript, jQuery
    Location:
    Everywhere
    So essentially you're looking for it to do this:

    input: (one two (three|four) five|six (seven|(eight|nine)|ten)|eleven|twelve)

    potential output(s):
    one two three five
    one two four five
    six seven
    six eight
    six nine
    six ten
    eleven
    twelve

    I have a function I recently wrote for spinning, but it doesn't handle nested expression arrays (that's what I call them). As is, if you pass it {a|b|c} it'll output a random selection from the set. {} are the default constraints. If this is what you're looking for and someone is down to spend an hour or so modifying it to handle nesting I don't mind, in fact I'd probably appreciate it. I don't have the time or mental energy to do it anytime soon unfortunately. Again if this is what you're looking for and no one modifies this I'll try to modify it next week.

    Code:
        function expressionarray($text, $constraints = '{}', $delimiter = '|') {
            if($text == '' || $delimiter == '' || ($constraints == '' || strlen($constraints) != 2)) { return; }
            
            $constraint = array(substr($constraints, 0, 1), substr($constraints, -1));
            
            $index = strpos($text, $constraint[0]);
            while($index !== false) {
                $index++;
                if($index > 1 && $closing == 0) { $output = substr($text, 0, $index - 1); }
                $closing = strpos($text, $constraint[1], $index);
                if($closing !== false) {
                    $contents = explode($delimiter, substr($text, $index, $closing - $index));
                    $output .= $contents[mt_rand(0, (count($contents) - 1))];
                    $closing++;
                    $index = strpos($text, $constraint[0], $closing);
                    if($index != 0 && ($index - $closing) > 0) { $output .= substr($text, $closing, $index - $closing); }
                    if($index == 0 && $closing <= strlen($text)) { $output .= substr($text, $closing, strlen($text) - ($closing - 1)); }
                } else {
                    $output .= substr($text, ($index - 1), strlen($text) - ($index - 2));
                    break;
                }
            }
            if($output == '') { $output = $text; }
            return $output;
        }
     
    Last edited: Feb 17, 2011
  11. easyroms

    easyroms Newbie

    Joined:
    Nov 5, 2009
    Messages:
    15
    Likes Received:
    1
    PHP Already handles matching braces (or nested braces). My example shows how to do this using preg_match
     
  12. altschule

    altschule Regular Member

    Joined:
    Sep 1, 2010
    Messages:
    282
    Likes Received:
    185
    Location:
    Sector 9
    Actually, that's not really the case when it could be nested multiple times. It actually took me months to find a somewhat answer to my problem and that was only the route to take, eventually I got it to work. Thanks for your input fellas.
     
  13. Crazy

    Crazy Jr. Executive VIP

    Joined:
    Jun 13, 2009
    Messages:
    640
    Likes Received:
    319
    Occupation:
    VB, C#, XHTML, CSS, PHP, MySQL, JavaScript, jQuery
    Location:
    Everywhere
    If you got it to work could you share what you did?
     
  14. easyroms

    easyroms Newbie

    Joined:
    Nov 5, 2009
    Messages:
    15
    Likes Received:
    1
    altschule, Show me the string you are trying to match and what the expected output is. I used your example string:
    Code:
    [var1=this;var2=that;var3=[subvar1=this;subvar2=that];var4=this]
    If used with my regex code, it will return the following match:
    Code:
    [var1=this;var2=that;var3=[subvar1=this;subvar2=that];var4=this]
    If your trying it on another string and it isnt working let me know what that is so I can double check the REGEX
     
  15. breonsnow

    breonsnow Newbie

    Joined:
    Sep 23, 2008
    Messages:
    39
    Likes Received:
    3
    sorry just a quick question can I add "/" to a REGEX expression?
     
  16. Crazy

    Crazy Jr. Executive VIP

    Joined:
    Jun 13, 2009
    Messages:
    640
    Likes Received:
    319
    Occupation:
    VB, C#, XHTML, CSS, PHP, MySQL, JavaScript, jQuery
    Location:
    Everywhere
    Still learning regex but so far I haven't seen / used as a metacharacter, so I'd say yes.
     
  17. altschule

    altschule Regular Member

    Joined:
    Sep 1, 2010
    Messages:
    282
    Likes Received:
    185
    Location:
    Sector 9
    You have to escape it with a \ like so: \/