Jump to content

Efficiency Advice


discomatt

Recommended Posts

I have a recursive function that parses template-like strings in loops. Here's a sample string

 

{start->container}
<some action here>
<some more>
{start->inner_left}
	<fill this with mysql data>
{end->inner_left}
{start->inner_right}
	<header stuff>
	{start->content}
		<inner stuff, more actions>
	{end->content)
	</header stuff>
 {end->inner_right}
<footer>
{end->container}

 

And here's my function (and some supporting code) That finds these loops recursively.

 

<?php

# preg_recursive
#	$component - Used elsewhere in the script
#	$subject - Subject text for recursive 'callback'
function preg_recursive ( $component, $subject ) {

# \1 - Content before loop
# \2 - Name of the loop
# \3 - Content within loop
# \4 - Content after loop
$regex = '/((??!{start->).)*+){start->([\\w]++)}((??!{end->\\2).)++){end->\\2}(.*+)/s';

# If no matches, or error, return false
if ( strpos($regex, '{start->') !== FALSE || ($count = preg_match_all($regex, $subject, $matches)) == 0 )
	return FALSE;

# Loop through matches
for ( $i = 0; $i < $count; $i++ ) {

	# Check for further depth
	if ( ($inner = preg_recursive($component, $matches[3][$i])) === FALSE )
		$inner = $matches[3][$i];

	# Execute an outside function to further parse the results
	return parse($component .'-'. $matches[2][$i], $matches[1][$i] . $inner . $matches[4][$i]);

	# Remove the # below and comment line 26 (above) to test
	# return $matches[1][$i] .'{start->'. $matches[2][$i] .'}'. $inner .'{end->'. $matches[2][$i] .'}'. $matches[4][$i];

}

}

# Sample template string... will be loaded from outside file
$template_string = <<<_TEMPLATE
{start->container}
<some action here>
<some more>
{start->inner_left}
	<fill this with mysql data>
{end->inner_left}
{start->inner_right}
	<header stuff>
	{start->content}
		<inner stuff, more actions>
	{end->content)
	</header stuff>
 {end->inner_right}
<footer>
{end->container}
_TEMPLATE;

# Call
echo preg_recursive( 'someComponent', $template_string );

?>

 

Here's the unescaped regex

 

((??!{start->).)*+){start->([\w]++)}((??!{end->\2).)++){end->\2}(.*+)

 

Is there any way to make this code more efficient? Or does it look fairly clean? Thanks in advance :)

Link to comment
Share on other sites

Here's a working version :) Sorry again

 

<?php

# preg_recursive
#	$component - Used elsewhere in the script
#	$subject - Subject text for recursive 'callback'
function preg_recursive ( $component, $subject ) {

# \1 - Centent before loop
# \2 - Name of the loop
# \3 - Content within loop
# \4 - Content after loop
$regex = '/((??!{start->).)*+){start->([\\w]++)}((??!{end->\\2).)++){end->\\2}(.*+)/s';

# If no matches, return unchanged string
if ( strpos($subject, '{start->') === FALSE || ($count = preg_match_all($regex, $subject, $matches, PREG_SET_ORDER)) == 0 )
	return $subject;

# Loop through matches
foreach ( $matches as $match ) {

	# Check for further depth
	$match[3] = preg_recursive( $component, $match[3] );
	# Return results - would usually be calling a function here for further parsing
	return $match[1] .'{s->'. $match[2] .'}'. $match[3] .'{e->'. $match[2] .'}'. $match[4];

}

}

# Sample template string... will be loaded from outside file
$template_string = <<<_TEMPLATE
{start->container}
<some action here>
<some more>
{start->inner_left}
	<fill this with mysql data>
{end->inner_left}
{start->inner_right}
	<header stuff>
	{start->content}
		<inner stuff, more actions>
	{end->content)
	</header stuff>
 {end->inner_right}
<footer>
{end->container}
_TEMPLATE;

# Call
echo preg_recursive( 'someComponent', $template_string );

?>

Link to comment
Share on other sites

I think this is more efficient--at least human-wise if not machine-wise--but benchmarks will tell the tale.

 

It first grabs the offsets it needs to examine with a fixed pattern, then jumps straight to those. The patterns are much simpler and no recursion is involved. You could even change the offset examination portion to use a strpos loop.

 

<pre>
<?php
$template_string = <<<_TEMPLATE
{start->container}
<some action here>
<some more>
{start->inner_left}
	<fill this with mysql data>
{end->inner_left}
{start->inner_right}
	<header stuff>
	{start->content}
		<inner stuff, more actions>
	{end->content}
	</header stuff>
 {end->inner_right}
<footer>
{end->container}
_TEMPLATE;

### Gather starting offsets.
preg_match_all('/{start->/', $template_string, $offsets, PREG_OFFSET_CAPTURE);
echo '<b>Offsets:</b><hr/>';
print_r($offsets[0]);
### Check each one.
foreach ($offsets[0] as $offset_arr) {
$offset = $offset_arr[1];
echo "<hr/><b>Checking $offset</b>...<br>";
if (preg_match('/\G{start->(\w+)}.+?{end->\1}/s', $template_string, $matches, NULL, $offset)) {
	foreach ($matches as &$match) {
		$match = htmlspecialchars($match);
	}
	print_r($matches);
}
}
?>
</pre>

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.