CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Regular Expressions:
conditional regexpr

 



PerlKid
stranger

Jun 14, 2001, 7:44 PM

Post #1 of 5 (5030 views)
conditional regexpr Can't Post

I'm working on a template module and one of the features is the support of IF conditionals. I'm having a problem with the regexp because it will gulp up all the IF tags at once...and that causes some very undesireable results.

ie...

Code
s/<%if\s(\w+)\s?(.{1,2})?\s?(\w+)%>(.+)<%endif%>/ 
complex($1,$2,$3,$4)
/sge;

would match:

Code
<%if foo eq bar%> 
some stuff
<%endif%>
<%if foo eq blah%>
some other stuff
<%endif%>

and NOT the two blocks seperately.

My question is this: How do I keep it from being greedy, and only match blocks of code that do NOT have IF tags in them, so that IF conditionals are matched begining with the innermost conditinional?

As of now, the only way I've found to do this is to actually put 'labels' to control the matches

ie..

Code
s/<%(\w+):\sif\s(\w+)\s?(.{1,2})?\s?(\w+)%>(.+)<%\1:\sendif%>/ 
complex($2,$3,$4,$5)
/sge;

evaluates each block and returns the result and then I run another regexpr to see if there were nested ifs, and then re-evaluate the template...

Code
<%foo1: if foo eq bar%> 
some stuff
<%foo1: endif%>
<%foo2: if foo eq blah%>
<%foo2a: if bar%>
the variable 'bar' exists
<%foo2a: endif%>
<%foo2: endif%>

You can see an example file, template, and the module at:
ftp://ftp.camelsoup.com/pub/parser/

--Drew
http://www.camelsoup.com

Code
s;[\d\$&(\^)];;g+s;\.; ;g+s;(.)(..);$2$1;g+print,if$_='&61k4I.)l6il.edn7(K2e^ny$';



PerlKid
stranger

Jun 14, 2001, 9:46 PM

Post #2 of 5 (5026 views)
Re: conditional regexpr [In reply to] Can't Post

I think I got it...


Code
$_= qq| 
<%if%>
foo
<%if%>
bar
<%end%>
foo
<%end%>
|;
{
s/
<%if%> #look for an if tag
( #get the content
.*
(?!<%if%>) #skip if we have child ifs
.*
)
<%end%> #look for an end tag
/
$1
/sgx;
(/<%if%>/) and ($i++ < 500) and redo; #check for nested ifs
#and stop in case of deep recursion
}
print;

--Drew
http://www.camelsoup.com

Code
s;[\d\$&(\^)];;g+s;\.; ;g+s;(.)(..);$2$1;g+print,if$_='&61k4I.)l6il.edn7(K2e^ny$';



mhx
Enthusiast

Jun 14, 2001, 9:54 PM

Post #3 of 5 (5026 views)
Re: conditional regexpr [In reply to] Can't Post

Hi Drew,

As you've realized, the problem is the greedy behaviour of the * and + operators. You can make these non-greedy by appending a ?.
So this should work:

Code
s/<%if\s(\w+)\s?(.{1,2})?\s?(\w+)%>(.+?)<%endif%>/  complex($1,$2,$3,$4)/sge;

Concerning the nested if's, I cannot currently think of a regex implementation. I think I read something about this in Jeff Friedl's book (and that it's not possible, at least in an easy way), but unfortunately I don't have it at my hands at the moment...
Hope this helps anyway.

-- Marcus



PerlKid
stranger

Jun 14, 2001, 10:03 PM

Post #4 of 5 (5025 views)
Re: conditional regexpr [In reply to] Can't Post

I can't believe I didn't try that! I've been trying to figure this out for a month.

Thanks a lot. Smile

--Drew
http://www.camelsoup.com

Code
s;[\d\$&(\^)];;g+s;\.; ;g+s;(.)(..);$2$1;g+print,if$_='&61k4I.)l6il.edn7(K2e^ny$';



PerlKid
stranger

Jul 3, 2001, 9:21 PM

Post #5 of 5 (5008 views)
Re: conditional regexpr [In reply to] Can't Post

UPDATE: after testing the provided suggestion further I realised that didn't work either.

I have got it working finally, though. It seems that I need to group the whole block of code in addition to the parameters.... and I'm also using a while loop instead of an anonymous sub and an re to check for more tags.

The complete working code I have now is:

Code
package CamelSoup::Template; 

use strict;
use vars qw($tag);

sub new {
my ($class, %tags) = @_;
($tag->{$_} = $tags{$_}) foreach (keys %tags);
return bless $tag, $class;
}

sub parse {
my ($tag, $file, $path, $temp) = (@_, '');
open (FILE, "$path/$file") or return ("Can't find file $path/$file: $!");
read FILE, $temp, 1024;
close (FILE);
while ($temp =~ /(<%include\s(.+?)%>)/) {
my ($block, $include, $out) = ($1, $2, '');
open (INC, "$path/$include") or return ("Can't find file $path/$file: $!");
read INC, $out, 1024;
close (INC);
$temp =~ s/$block/$out/e;
}
while ($temp =~ /(<%set\s(\w+)%>(.+?)<%endset%>)/) {
my ($block, $var, $out) = ($1, $2, $3);
$tag->{$var} = $out;
$temp =~ s/$block/''/e;
}
while ($temp =~ /(<%if\s(\w+)\s?([^\s]+)?\s?(\w+)?%>(.+?)<%endif%>)/s) {
my ($block, $var, $op, $val, $out, $show) = ($1, $2, $3, $4, $5, '');
if ($op) {
if ($op eq 'eq') { ($tag->{$var} eq $val) and $show++; }
elsif ($op eq 'ne') { ($tag->{$var} ne $val) and $show++; }
elsif ($op eq 'gt') { ($tag->{$var} gt $val) and $show++; }
elsif ($op eq 'lt') { ($tag->{$var} lt $val) and $show++; }
elsif ($op eq 'ge') { ($tag->{$var} ge $val) and $show++; }
elsif ($op eq 'le') { ($tag->{$var} le $val) and $show++; }
elsif ($op eq '==') { ($tag->{$var} == $val) and $show++; }
elsif ($op eq '!=') { ($tag->{$var} != $val) and $show++; }
elsif ($op eq '>') { ($tag->{$var} > $val) and $show++; }
elsif ($op eq '<') { ($tag->{$var} < $val) and $show++; }
elsif ($op eq '>=') { ($tag->{$var} >= $val) and $show++; }
elsif ($op eq '<=') { ($tag->{$var} <= $val) and $show++; }
elsif ($op eq 'and') { ($tag->{$var} and $tag->{$val}) and $show++; }
elsif ($op eq 'or') { ($tag->{$var} or $tag->{$val}) and $show++; }
elsif ($op eq '=~') { ($tag->{$var} =~ $val) and $show++; }
elsif ($op eq '!~') { ($tag->{$var} !~ $val) and $show++; }
else { ($out = "malformed condition: 'if $var $op $val'") and $show++; }
} else { defined $tag->{$var} and $show++; }
$temp =~ s/$block/$out if $show/e;
}
while ($temp =~ /(<%(\w+)%>)/) {
my ($block, $var, $out) = ($1, $2, '');
(defined $tag->{$var}) ? ($out = $tag->{$var}) : ($out = "unknown variable: '$var'");
$temp =~ s/$block/$out/e;
}
return $temp;
}

sub strip_blanks { return join "\n", grep { !/^\s*$/ } split /\n/, pop; }
1;

comments or suggestions would be appreciated.

--Drew
http://www.camelsoup.com

Code
s;[\d\$&(\^)];;g+s;\.; ;g+s;(.)(..);$2$1;g+print,if$_='&61k4I.)l6il.edn7(K2e^ny$';


 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives