How to go about this? REGEX & PHP

altschule

Regular Member
Joined
Sep 1, 2010
Messages
282
Reaction score
186
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:
#\[(.*?)\[(.*?)\](.*?)\]
 
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
                )

        )

)
 
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.
 
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
 
Last edited:
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.

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.
 
Last edited:
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...
 
here you go.

PHP:
if(preg_match('/\[(?>[^\[\]]+|(?R))*\]/i',"[var1=this;var2=that;var3=[subvar1=this;subvar2=that];var4=this]",$matches))
{
  var_dump($matches);
}
 
I'm interested - what sort of a template engine are you building?
 
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...
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:
PHP Already handles matching braces (or nested braces). My example shows how to do this using preg_match
 
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.
 
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.
If you got it to work could you share what you did?
 
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
 
Back
Top