Template-parser foreach
laatste post te kijken.
Hallo,
Ik heb momenteel een simpele template parser gemaakt die doet wat hij moet doen. Nu zou ik er toch nog een kleine toevoeging aan willen doen, waardoor ik werkelijk alle HTML zou kunnen scheiden van mijn PHP-code.
Nu, ik écht onhandig met regexxen en kom er niet bepaald goed uit. Ik ben momenteel wat aan het testen, maar het lukt me niet helemaal. Mijn bedoeling is dat de volgende syntaxis wordt gebruikt: (voorbeeldje)
Ik ben alvast de volgende regex uitgekomen:
/{\$([A-Z0-9_-]+)@([A-Z0-9_-]+)}(.+?)\{\$([A-Z0-9_-]+)}/s
Nu, dat is nog niet helemaal wat ik wil. Momenteel kan er maar 1x @ gebruikt worden. Terwijl dit eigenlijk ongelimiteerd x zou moeten lukken.
Update Gelieve naar mijn Hallo,
Ik heb momenteel een simpele template parser gemaakt die doet wat hij moet doen. Nu zou ik er toch nog een kleine toevoeging aan willen doen, waardoor ik werkelijk alle HTML zou kunnen scheiden van mijn PHP-code.
Nu, ik écht onhandig met regexxen en kom er niet bepaald goed uit. Ik ben momenteel wat aan het testen, maar het lukt me niet helemaal. Mijn bedoeling is dat de volgende syntaxis wordt gebruikt: (voorbeeldje)
Code (php)
1
2
3
2
3
{$FOREACH_USERS@username@mail@gsm}
'Username: {@username} mail: {@mail} gsm: {@gsm} <br />
{$FOREAH_USERS}
'Username: {@username} mail: {@mail} gsm: {@gsm} <br />
{$FOREAH_USERS}
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<?php
/* in PHP zou ik dat dan als volgt doen */
$oTemplate->addForeach('foreach_users', array('usern' => 'Write', 'mail' => '[email protected]', 'gsm' => '0000000001'));
/* Uiteraard met meer dan 1 user */
?>
/* in PHP zou ik dat dan als volgt doen */
$oTemplate->addForeach('foreach_users', array('usern' => 'Write', 'mail' => '[email protected]', 'gsm' => '0000000001'));
/* Uiteraard met meer dan 1 user */
?>
Ik ben alvast de volgende regex uitgekomen:
/{\$([A-Z0-9_-]+)@([A-Z0-9_-]+)}(.+?)\{\$([A-Z0-9_-]+)}/s
Nu, dat is nog niet helemaal wat ik wil. Momenteel kan er maar 1x @ gebruikt worden. Terwijl dit eigenlijk ongelimiteerd x zou moeten lukken.
Gewijzigd op 12/08/2011 16:31:55 door Write Down
Je hoort geen REGEX te gebruiken voor een parser.
Toevoeging op 11/08/2011 21:14:59:
Niemand? Het geen waar ik eigenlijk iets moet op vinden is het volgende stukje: @([A-Z0-9_-]+)
Dat stukje zou zich meermaals moeten kunnen herhalen, en hoe ik dat kan bereiken, weet ik niet :(.
Toevoeging op 12/08/2011 11:15:39:
Ik heb enige vooruitgang geboekt, maar volgens mij kan het eenvoudiger:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
<?php
$sTest = '{$FOREACH@KEY1@KEY2@KEY3}
blabla
{$FOREACH}
';
preg_match('/{\$([A-Z0-9_-]+)(.+?)}(.+?)\{\$([A-Z0-9_-]+)}/s', $sTest, $aArr);
preg_match_all('/@([A-Z0-9_-]+)/s', $aArr[2], $aArr);
echo '<pre>';
print_r($aArr);
echo '</pre>';
?>
$sTest = '{$FOREACH@KEY1@KEY2@KEY3}
blabla
{$FOREACH}
';
preg_match('/{\$([A-Z0-9_-]+)(.+?)}(.+?)\{\$([A-Z0-9_-]+)}/s', $sTest, $aArr);
preg_match_all('/@([A-Z0-9_-]+)/s', $aArr[2], $aArr);
echo '<pre>';
print_r($aArr);
echo '</pre>';
?>
Gewijzigd op 11/08/2011 15:10:07 door Write Down
Code (php)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
<?php
$sTest = '{$FOREACH}
<tr><td>@KEY1</td><td>@KEY2</td><td>@KEY3</td></tr>
{$FOREACH}
';
preg_match('/{\$([A-Z0-9_-]+)}(.+?)\{\$([A-Z0-9_-]+)}/s', $sTest, $aArr);
echo '<pre>';
print_r($aArr);
echo '</pre>';
?>
$sTest = '{$FOREACH}
<tr><td>@KEY1</td><td>@KEY2</td><td>@KEY3</td></tr>
{$FOREACH}
';
preg_match('/{\$([A-Z0-9_-]+)}(.+?)\{\$([A-Z0-9_-]+)}/s', $sTest, $aArr);
echo '<pre>';
print_r($aArr);
echo '</pre>';
?>
Output geeft dan:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
Array
(
[0] => {$FOREACH}
@KEY1@KEY2@KEY3
{$FOREACH}
[1] => FOREACH
[2] =>
@KEY1@KEY2@KEY3
[3] => FOREACH
)
(
[0] => {$FOREACH}
@KEY1@KEY2@KEY3
{$FOREACH}
[1] => FOREACH
[2] =>
@KEY1@KEY2@KEY3
[3] => FOREACH
)
Probleem is dat ik dan de cellen van de tabel verlies, wat ik eigenlijk ook nog nodig heb...
Toevoeging op 12/08/2011 16:48:54:
Heb nog wat verder geprutst, maar volgens mij kan het allemaal nog een stuk eenvoudiger. Even wel vermelden, dit is echt test-code, uiteraard zet ik dit nog om naar een mooie class.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
$aTest = array(
'slt1' => 'hoi',
'slt2' => 'hej',
'slt3' => 'hi'
);
$sTest = '{$FOREACH}
<tr><td>{@KEY1}</td><td>{@KEY2}</td><td>{@KEY3}</td></tr>
{$FOREACH}
';
preg_match('/{\$([A-Z0-9_-]+)}(.+?)\{\$([A-Z0-9_-]+)}/s', $sTest, $aArrO);
echo '<pre>';
print_r($aArrO);
echo '</pre><hr />';
preg_match_all('/{\@([A-Z0-9_-]+)}/s', $aArrO[2], $aArr);
echo '<pre>';
print_r($aArr[0]);
echo '</pre><hr />';
$sReplace = str_replace('{$'.$aArrO[1].'}', '', $sTest);
echo '<table>';
echo str_replace($aArr[0], $aTest, $sReplace);
echo '</table>';
?>
$aTest = array(
'slt1' => 'hoi',
'slt2' => 'hej',
'slt3' => 'hi'
);
$sTest = '{$FOREACH}
<tr><td>{@KEY1}</td><td>{@KEY2}</td><td>{@KEY3}</td></tr>
{$FOREACH}
';
preg_match('/{\$([A-Z0-9_-]+)}(.+?)\{\$([A-Z0-9_-]+)}/s', $sTest, $aArrO);
echo '<pre>';
print_r($aArrO);
echo '</pre><hr />';
preg_match_all('/{\@([A-Z0-9_-]+)}/s', $aArrO[2], $aArr);
echo '<pre>';
print_r($aArr[0]);
echo '</pre><hr />';
$sReplace = str_replace('{$'.$aArrO[1].'}', '', $sTest);
echo '<table>';
echo str_replace($aArr[0], $aTest, $sReplace);
echo '</table>';
?>
Gewijzigd op 12/08/2011 16:31:02 door Write Down
De syntaxis die ik gebruik is de volgende geworden:
Vanuit mijn template-parser (een klasse) roep ik in de constuctor een callback functie aan, als volgt:
Code (php)
1
2
3
2
3
<?php
$this->_sOutput = preg_replace_callback('/{\$([A-Z0-9_-]+)@START}(.+?)\{\$([A-Z0-9_-]+)@STOP}/s', array($this, 'replaceForeach'), $this->_sOutput);
?>
$this->_sOutput = preg_replace_callback('/{\$([A-Z0-9_-]+)@START}(.+?)\{\$([A-Z0-9_-]+)@STOP}/s', array($this, 'replaceForeach'), $this->_sOutput);
?>
En de "replaceForeach" ziet er dan als volgt uit, let wel op dat mijn code nog niet al te netjes is!
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private function replaceForeach($aMatch) {
$iStart = strpos($this->_sContent, '{$'.$aMatch[1].'@START}') + strlen(('{$'.$aMatch[1].'@START}'));
$iStop = strpos($this->_sContent, '{$'.$aMatch[1].'@STOP}', $iStart);
$this->_sForeach = substr($this->_sContent, $iStart, $iStop - $iStart);
preg_match_all('/{\@([A-Z0-9_-]+)}/', $this->_sForeach, $this->_aForeach);
$gegevens = count($this->_aReplacements[strtolower($aMatch[1])]);
$replacements = count($this->_aForeach[0]);
$rijen = $gegevens/$replacements;
$vervang_geg = $this->_aReplacements[strtolower($aMatch[1])];
$complete_output = '';
for ($rij = 0; $rij < $rijen; $rij++) {
$huidige_rij = $gegevens-($rij*$replacements);
$start = $gegevens-$huidige_rij;
for ($replace_start = 0; $replace_start < $replacements; $replace_start++) {
$index = $start + $replace_start;
$output_rij[$replace_start] = $vervang_geg[$index];
}
$complete_output .= str_replace($this->_aForeach[0], $output_rij, $this->_sForeach);
}
return $complete_output;
}
$iStart = strpos($this->_sContent, '{$'.$aMatch[1].'@START}') + strlen(('{$'.$aMatch[1].'@START}'));
$iStop = strpos($this->_sContent, '{$'.$aMatch[1].'@STOP}', $iStart);
$this->_sForeach = substr($this->_sContent, $iStart, $iStop - $iStart);
preg_match_all('/{\@([A-Z0-9_-]+)}/', $this->_sForeach, $this->_aForeach);
$gegevens = count($this->_aReplacements[strtolower($aMatch[1])]);
$replacements = count($this->_aForeach[0]);
$rijen = $gegevens/$replacements;
$vervang_geg = $this->_aReplacements[strtolower($aMatch[1])];
$complete_output = '';
for ($rij = 0; $rij < $rijen; $rij++) {
$huidige_rij = $gegevens-($rij*$replacements);
$start = $gegevens-$huidige_rij;
for ($replace_start = 0; $replace_start < $replacements; $replace_start++) {
$index = $start + $replace_start;
$output_rij[$replace_start] = $vervang_geg[$index];
}
$complete_output .= str_replace($this->_aForeach[0], $output_rij, $this->_sForeach);
}
return $complete_output;
}
Volgens mij kan de bovenstaande code echter nog een heel stuk eenvoudiger.
Waarom wil je iegenlijk een eigen template parser bouwen? :)
Write Down op 11/08/2011 15:07:39:
Wat dan wel? voor zover ik weet doet Smarty het ook met regex'en?
Toevoeging op 11/08/2011 21:14:59:
Niemand? Het geen waar ik eigenlijk iets moet op vinden is het volgende stukje: @([A-Z0-9_-]+)
Dat stukje zou zich meermaals moeten kunnen herhalen, en hoe ik dat kan bereiken, weet ik niet :(.
Toevoeging op 12/08/2011 11:15:39:
Ik heb enige vooruitgang geboekt, maar volgens mij kan het eenvoudiger:
Toevoeging op 11/08/2011 21:14:59:
Niemand? Het geen waar ik eigenlijk iets moet op vinden is het volgende stukje: @([A-Z0-9_-]+)
Dat stukje zou zich meermaals moeten kunnen herhalen, en hoe ik dat kan bereiken, weet ik niet :(.
Toevoeging op 12/08/2011 11:15:39:
Ik heb enige vooruitgang geboekt, maar volgens mij kan het eenvoudiger:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
<?php
$sTest = '{$FOREACH@KEY1@KEY2@KEY3}
blabla
{$FOREACH}
';
preg_match('/{\$([A-Z0-9_-]+)(.+?)}(.+?)\{\$([A-Z0-9_-]+)}/s', $sTest, $aArr);
preg_match_all('/@([A-Z0-9_-]+)/s', $aArr[2], $aArr);
echo '<pre>';
print_r($aArr);
echo '</pre>';
?>
$sTest = '{$FOREACH@KEY1@KEY2@KEY3}
blabla
{$FOREACH}
';
preg_match('/{\$([A-Z0-9_-]+)(.+?)}(.+?)\{\$([A-Z0-9_-]+)}/s', $sTest, $aArr);
preg_match_all('/@([A-Z0-9_-]+)/s', $aArr[2], $aArr);
echo '<pre>';
print_r($aArr);
echo '</pre>';
?>
Regex is veelste ingewikkelt om een template parser mee te bouwen, het kan geen sytax errors mee opsporen, etc.
http://stackoverflow.com/questions/3887548/need-to-optimize-regex-for-a-template-parser
Gewijzigd op 15/08/2011 10:03:10 door Fabian M
Ik ben er mij van bewust dat er een aantal goede parsers op het web zijn, met uitstek Smarty. Ik ben echter van mening dat deze te uitgebreid is, van heel het Smarty gebeuren heb ik amper een paar functies nodig. Verder is het natuurlijk ook gewoon leuk om zelf één te maken en daardoor kennis te verwerven. Waarom maken mensen een eigen CMS, buiten het feit dat het te commercialiseren is?
@Fabian
Ik heb even de informatie doorgenomen en wat verder gezocht. Ik moet je gelijk geven, hoe dieper je wilt gaan, hoe lastiger en hoe lastiger het is om met een regex het werkje te klaren. Echter, net als in één van de reacties stond, ik hoef zo diep niet te gaan. Overigens komt er in de andere functies van template parser geen regex voor, wat de prestaties dus toch nog relatief goed zou moeten houden.