having trouble with preg_match_all() [solved]

Any questions involving matching text strings to patterns - the pattern is called a "regular expression."

Moderator: General Moderators

Post Reply
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

having trouble with preg_match_all() [solved]

Post by s.dot »

Code: Select all

if(preg_match_all("/(\{if(.+?)\}.+?\{\/if\})/ism", $src, $matches))
This code produces me a very nice nested array. Unfortunately, I'm having troubles iterating through this array using correct array indexes.

I'd think it was a PHP bug in my version, but I know how php ignorant I am. I've tried many for() and foreach() loops, many print_r()'s and many hours with a headache.

What is the correct way to loop through $matches and get the value of (.+?) in the regex, for each set of matches that preg_match_all() finds?

... I probably just need sleep.

Here's my current coding after hours of deleting, editing, & trying again.

Code: Select all

private function _replace_if($src)
{
	if(preg_match_all("/(\{if(.+?)\}.+?\{\/if\})/ism", $src, $matches))
	{
		//	echo '<pre>';
			print_r($matches);
		//	echo '</pre>';
		for($i = 0; $i < count($matches); $i++)
		{
			$statement = str_replace(array('(', ')'), '', $matches[2][$i]);
			if(eval("return $statement;"))
			{
				echo 'true';
				//$src = str_replace('{if(' . $statement . '}
			} else
			{
				echo 'false';
			}
		}
	}
}
If you can't tell, it's a primitive template engine. Any other ways to evaluate {if ..} {/if} without using regexes without preg_* would be appreciated also.
Last edited by s.dot on Tue Jul 24, 2007 10:37 pm, edited 1 time in total.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
stereofrog
Forum Contributor
Posts: 386
Joined: Mon Dec 04, 2006 6:10 am

Post by stereofrog »

It appears to me that you need preg_replace_callback here rather than preg_match_all and a loop.
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Post by s.dot »

Thanks, I will give that a try.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Post by s.dot »

So, I've got this.

Code: Select all

private function _replace_if($src)
{
	if(preg_match("/(\{if\((.+?)\)\}.+?\{\/if\})/ism", $src))
	{
		preg_replace_callback("/(\{if\((.+?)\)\}.+?\{\/if\})/ism",
			create_function(
				'$matches',
				'if(eval("return $matches[2];")){ echo \'true\'; } else { str_replace(\'i\', \'X\', "\$src"); }'
			),
			$src
		);
		
	}
}
It seems I can't get the varialbe $src to be abled to be passed to str_replace. I either get undefined variable $src or I litterally get '$src'.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
stereofrog
Forum Contributor
Posts: 386
Joined: Mon Dec 04, 2006 6:10 am

Post by stereofrog »

Hm.... honestly I don't get what you're after exactly. Here's a small example of how this _could_ look like, hope it helps.

Code: Select all

$text = "
1
{if 10 > 5} foo {/if}
2
{if 10 > 50} bar {/if}
3
";

function _compile_if($x) {
	$cond = eval("return $x[1];");
	return $cond ? $x[2] : '';
}
$new_text = preg_replace_callback(
	"~{if(.+?)}(.+?){/if}~si",
	'_compile_if',
	$text);
	
echo $new_text; // prints 1 foo 2 3
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Post by s.dot »

Wow,

Finally got it with:

Code: Select all

private function _replace_if($src)
{
	if(preg_match("#\{if\((.+?)\)\}(.+?)\{/if\}#ism", $src))
	{
		$src = preg_replace_callback(
			"#\{if\((.+?)\)\}(.+?)\{/if\}#ism",
			create_function(
				'$matches',
				'$statement = eval("return $matches[1];");
				return $statement ? $matches[2] : \'\';'
			),
		$src);
	}
	
	return $src;
}
My trouble was with understanding how exactly preg_replace_callback() works. Thanks a lot stereofrog!!
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Post by s.dot »

Question on how I can get nested ifs to work...

IE

Code: Select all

{if($foo == 1)}
   say hi
   {if($bar == 2)}
       say what's up
   {/if}
{/if}
You can see how the regex finds the first {/if} and stops.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
superdezign
DevNet Master
Posts: 4135
Joined: Sat Jan 20, 2007 11:06 pm

Post by superdezign »

Tokenization, which is what you should have been using in the first place.
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Post by s.dot »

I think I'm going to rewrite my whole templating engine thus far.
Need to study this tokenizing thing.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
superdezign
DevNet Master
Posts: 4135
Joined: Sat Jan 20, 2007 11:06 pm

Post by superdezign »

scottayy wrote:I think I'm going to rewrite my whole templating engine thus far.
Need to study this tokenizing thing.
Hehe, okay. I just recently wrote a basic template engine for a website I'm producing. So you know, it was extremely difficult for me to find any resources that explained *how* to tokenize content. There are plenty that explain *what* tokenization is though. I had to figure it out on my own. Eventually, I'd like to write an entire tokenizer class, but I don't quite feel like putting in the work yet.
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Post by s.dot »

I think I'm trying to rush through it. Instead I need to realize that this is a very important aspect of my project, and take my time with it.

Did you find any good examples or tutorials? I'm googling right now, but you may have found something good in your search that I might not find.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
superdezign
DevNet Master
Posts: 4135
Joined: Sat Jan 20, 2007 11:06 pm

Post by superdezign »

Actually, no. I never found much of anything other than concepts and Delphi code, but I did read one professor's notes that mentioned recursion and suddenly, it just clicked.
User avatar
stereofrog
Forum Contributor
Posts: 386
Joined: Mon Dec 04, 2006 6:10 am

Post by stereofrog »

scottayy wrote:Question on how I can get nested ifs to work...
Depends on what your conditions look like. If you don't allow arbitrary strings between {if ... and matching }, you can use something like below to handle nested constructs:

Code: Select all

$r_if = '~
	{if ([^{}]+) }
		(
			(. (?! {if ) ) *?
		)
	{/if}
~six';

while(preg_match($r_if, $text))
	$text = preg_replace_callback(
        $r_if,
        '_compile_if',
        $text);


If you're going to allow free-form syntax like php itself has, you'll need lexer and parser. While the former is trivial thanks to regular expressions, the latter requires some "advanced" skills, like understanding recursion, stacks, formal grammars and all that stuff.

The terms for further googling are: lexer, php lexer, yacc, lemon parser, php parser generator.

Hope this helps.
Post Reply