Nieuws:

Welkom, Gast. Alsjeblieft inloggen of registreren.
Heb je de activerings-mail niet ontvangen?

Auteur Topic: [ Opgelost ] PHP RegExp if-lussen parsen  (gelezen 861 keer)

[ Opgelost ] PHP RegExp if-lussen parsen
« Gepost op: 2010/06/20, 19:16:57 »
Hallo iedereen,

Voor een behoorlijk grote applicatie wil ik templates parsen, en wil hierin ook if-lussen gebruiken. Dit werkt in principe. Ik heb een flinke poos geleden hiervoor een zeer lastige regex geschreven:

/if\s{0,}\([\s\n]{0,}(.*?)[\s\n]{0,}(==|\!=|\>|\<|\<=|\>=)[\s\n]{0,}(.*?)[\s\n]{0,}\)[\s\n]{0,}\{[\s\n]{0,}(.*?)[\s\n]{0,}\}(;|(\s{0,}(else)\s{0,}\{\s{0,}(.*?)\s{0,}\};))/si
Een voorbeeld template:
if( "aa" == "aa" ) {
     if( "bb" == "bb" ) {
          blaat
     };
};

Het probleem is dat hij nu het eerste beste sluithaakje gebruikt '};'.  Daardoor vind het script ook maar één if-lus. Als ik dus slechts één if gebruik of ze onder elkaar zet werkt het wel.

Heeft iemand misschien een idee hoe het eventueel wel gaat werken? Het hoeft niet perse met deze regex en wellicht is er meer nodig dan alleen een regex. Ik hoop dat iemand mij kan helpen :)
« Laatst bewerkt op: 2010/06/20, 21:28:45 door Koen Bokern »

Offline Rachid

  • Lid
    • rachidbm
    • Mijn blog
Re: [PHP] RegExp if-lussen parsen
« Reactie #1 Gepost op: 2010/06/20, 19:34:00 »
Voor dit soort dingen is het handig een "Stack" te gebruiken.
Elke { zet je dan op de stack (push), en elke keer als je een } tegenkomt doe je een pop.
Ben je ook blij dat Ubuntu zo toegankelijk en gratis is, en wil je graag net als ik iets terugdoen, kijk dan eens rond bij mwanzo, dé poort naar het bijdragen aan Ubuntu en haar gemeenschap!

Re: [PHP] RegExp if-lussen parsen
« Reactie #2 Gepost op: 2010/06/20, 20:27:53 »
Dat is inderdaad precies wat ik wil :) Alleen weet ik niet hoe ik het moet toepassen...

Ik heb nu zoiets om precies aan te geven op welke 'laag' wat staat:
for($pointer = 0; $pointer < strlen($text); $pointer ++)
{
$char  = $text[$pointer];
$nchar = $text[$pointer+1];
if($continue) continue;
$continue = false;

if($char == '{')
{
$new_text .= '[[[level:'.$level.']]]';
$level ++;
$level_top ++;
}

elseif($char == '}' && $nchar == ';')
{
$level --;
$new_text .= '[[[endlevel:'.$level.']]]';
$continue = true;
}

else
{
$new_text .= $char;
}

}

Echter nog niet gelukt om hiermee ook daadwerkelijk die iflussen goed te parsen.

Re: [PHP] RegExp if-lussen parsen
« Reactie #3 Gepost op: 2010/06/20, 21:27:19 »
:D Opgelost.. Bovenstaande code enigzins verbeterd en een nieuwe regex gemaakt voor de if-clause...

Nu heb ik echt een hoop keren overnieuw geprobeerd om dit probleem op te lossen en ik heb steeds opgegeven. Nu heb ik dit topic geplaatst en opeens lukt het ;)

Voor mensen die nieuwsgierig zijn post ik de werkende code, het is wel wat rommelig omdat het een testcode is:
<?php
ini_set
('error_reporting'1);
echo 
'<pre>';
$text '
if( "aaa" == "baaa" ) {
if( "bb" == "bbc" ) {
kaas
};
brood
} else {
jan
};

if( "cc" == "csc" ) {
 vis
};
'
;

$new_text "";
$level 0;
$level_top 0;
$continue false;

for(
$pointer 0$pointer strlen($text); $pointer ++)
{
$char  $text[$pointer];
$nchar $text[$pointer+1];
if($continue
{
$continue false;
continue;
}

if($char == '{')
{
$new_text .= '[[[level:'.$level.']]]';
$level ++;
$level_top ++;


elseif($char == '}' && $nchar == ';')
{
$level --;
$new_text .= '[[[endlevel:'.$level.']]][[[endif:'.$level.']]]';
$continue true;


elseif($char == '}')
{
$level --;
$new_text .= '[[[endlevel:'.$level.']]]';
}

else 
{
$new_text .= $char;
}

}

echo 
$new_text.'<hr><hr>';

for(
$level 0$level <= $level_top$level++)
{
$ot '\[\[\[level:'.$level.'\]\]\]';
$ct '\[\[\[endlevel:'.$level.'\]\]\]';
$ei '\[\[\[endif:'.$level.'\]\]\]';

$new_text preg_replace_callback('/if[\s]*\([\s\n]{0,}(.*?)[\s\n]{0,}(==|\!=|\>|\<|\<=|\>=)[\s\n]{0,}(.*?)[\s\n]{0,}\)[\s]*'.$ot.'(.*?)'.$ct.'('.$ei.'|[\s]*(else)[\s]*'.$ot.'(.*?)'.$ct.$ei.')/si''test'$new_text);

}

function 
test($matches)
{
$omatches $matches;
//$matches = $this->parse_matches($matches);
//if($this->debug) {
echo '<pre>';print_r($matches).'</pre>';
//}
switch($matches[2]) {
case '==':
if($matches[1]==$matches[3]) {
return $omatches[4];
} elseif(isset($matches[6]) && $matches[6]=='else') {
return $omatches[7];
}
break;
case '!=':
if($matches[1]!=$matches[3]) {
return $omatches[4];
} elseif(isset($matches[6]) && $matches[6]=='else') {
return $omatches[7];
}
break;
case '>':case '<':case '<=': case '>=':
$a preg_replace('/[^0-9]+/'''$matches[1]);
$b preg_replace('/[^0-9]+/'''$matches[3]);
if( ($matches[2]=='>' && $a $b) || ($matches[2]=='<' && $a $b) || ($matches[2]=='<=' && $a <= $b) || ($matches[2]=='>=' && $a >= $b) ) {
return $omatches[4];
} elseif(isset($matches[6]) && $matches[6]=='else') {
return $omatches[7];
}
break;
}
}
echo 
'<hr />out<hr />';
echo 
$new_text;