Content parsen preg_replace, raad ermee?
Ik ben momenteel een template-parser aan het maken. Lekker eenvoudig, maar handig :-). Alles is in OOP geschreven, maar het stukje waar ik nu aan bezig ben, wil ik eerst toch even met wat procedurele code uittesten. Tot daar het koffiepraatje.
Als input heb ik bv. het volgende: (afkomstig van een TPL-bestand)
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<h1>{$TITLE}</h1>
<h2>{$SUBTITLE}</h2>
<p class="headermenu">
<a href="#">Testje1</a>
<a href="#">Testje2</a>
</p>
<h2>{$SUBTITLE}</h2>
<p class="headermenu">
<a href="#">Testje1</a>
<a href="#">Testje2</a>
</p>
{$TITLE}, {$SUBITLTE} en eigenlijk alles wat de syntaxis {$[A-Z]} zet heeft moet vervangen worden. De te vervangen deeltjes worden uitgespuwd onder de vorm van een array. Bijvoorbeeld:
De parser zou dit dus moeten omzetten in het volgende:
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<h1>phpHulp.nl</h1>
<h2>phpHulp Forum}</h2>
<p class="headermenu">
<a href="#">Testje1</a>
<a href="#">Testje2</a>
</p>
<h2>phpHulp Forum}</h2>
<p class="headermenu">
<a href="#">Testje1</a>
<a href="#">Testje2</a>
</p>
Ik ga er vanuit dat ik dit met de preg_replace functie moet kunnen fixen.
Ik dacht iets in de aard van:
Echter krijg ik hiermee niet het gewenste resultaat.
Iets wat ik naar de toekomst ook wil gaan doen is {$[A-Z]#[0-9]} gaan replacen. Maar ik denk dat ik al best eerst is naar de "gewone" replace kijk :-).
Alvast bedankt (al is het maar dat je het gelezen hebt!)
Gewijzigd op 15/01/2011 18:57:17 door Noppes Homeland
preg_replace_callback het makkelijkst is, (je kan ook preg_replace met de e-modifier gebruiken, maar weet waar je mee bezig bent dan!)
Anyway, omdat ik dat laatste nooit doe, heb ik het voor de grap nu wel eens gedaan:
de e-modifier zorgt ervoor dat je replace-stukje van preg-replace wordt uitgevoerd alsof het PHP is. $1 wordt vervangen met de variabelenaam, dus ${strtolower("TITLE")} wordt uitgevoerd, wat weer hetzelfde is uiteindelijk als $title.
Ter vergelijking, als je het (mooi?) wilt doen met preg_replace_callback:
Ik heb de class wel nodig omdat ik ergens moet opslaan wat die variabelen voor waarde moeten krijgen, en ik die niet mee kan geven aan de functie zelf (want ik kan niet regelen welke argumenten replaceVariable meekrijgt) Of je moet globals daarvoor gebruiken, of closures als je PHP 5.3 hebt.
Ik denk dat Anyway, omdat ik dat laatste nooit doe, heb ik het voor de grap nu wel eens gedaan:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
$content = <<<'HTML'
<h1>{$TITLE}</h1>
<h2>{$SUBTITLE}</h2>
<p class="headermenu">
<a href="#">Testje1</a>
<a href="#">Testje2</a>
</p>
HTML;
$title = 'PHPhulp';
$subtitle = 'Geen idee';
echo preg_replace('/{\$([A-Z]+)}/e', '\${strtolower("$1")}', $content);
?>
$content = <<<'HTML'
<h1>{$TITLE}</h1>
<h2>{$SUBTITLE}</h2>
<p class="headermenu">
<a href="#">Testje1</a>
<a href="#">Testje2</a>
</p>
HTML;
$title = 'PHPhulp';
$subtitle = 'Geen idee';
echo preg_replace('/{\$([A-Z]+)}/e', '\${strtolower("$1")}', $content);
?>
de e-modifier zorgt ervoor dat je replace-stukje van preg-replace wordt uitgevoerd alsof het PHP is. $1 wordt vervangen met de variabelenaam, dus ${strtolower("TITLE")} wordt uitgevoerd, wat weer hetzelfde is uiteindelijk als $title.
Ter vergelijking, als je het (mooi?) wilt doen met preg_replace_callback:
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
class Template
{
private $template;
private $data = array();
public function __construct($template)
{
$this->template = $template;
}
public function set($name, $value)
{
$this->data[$name] = $value;
}
public function render()
{
return preg_replace_callback('/{\$([A-Z]+)}/', array($this, 'replaceVariable'), $this->template);
}
private function replaceVariable($match)
{
return $this->data[strtolower($match[1])];
}
}
$content = <<<'HTML'
<h1>{$TITLE}</h1>
<h2>{$SUBTITLE}</h2>
<p class="headermenu">
<a href="#">Testje1</a>
<a href="#">Testje2</a>
</p>
HTML;
$template = new Template($content);
$template->set('title', 'PHPhulp');
$template->set('subtitle', 'Geen idee');
echo $template->render();
?>
class Template
{
private $template;
private $data = array();
public function __construct($template)
{
$this->template = $template;
}
public function set($name, $value)
{
$this->data[$name] = $value;
}
public function render()
{
return preg_replace_callback('/{\$([A-Z]+)}/', array($this, 'replaceVariable'), $this->template);
}
private function replaceVariable($match)
{
return $this->data[strtolower($match[1])];
}
}
$content = <<<'HTML'
<h1>{$TITLE}</h1>
<h2>{$SUBTITLE}</h2>
<p class="headermenu">
<a href="#">Testje1</a>
<a href="#">Testje2</a>
</p>
HTML;
$template = new Template($content);
$template->set('title', 'PHPhulp');
$template->set('subtitle', 'Geen idee');
echo $template->render();
?>
Ik heb de class wel nodig omdat ik ergens moet opslaan wat die variabelen voor waarde moeten krijgen, en ik die niet mee kan geven aan de functie zelf (want ik kan niet regelen welke argumenten replaceVariable meekrijgt) Of je moet globals daarvoor gebruiken, of closures als je PHP 5.3 hebt.
Gewijzigd op 15/01/2011 19:19:29 door Jelmer -
Pas inderdaad écht heel erg op met de e modifier. Phphulp is in de bèta gehackt doordat in een reguliere expressie de e modifier werd gebruikt.
Ik ga het deze avond is rustig bekijken.
@Noppes Homeland
Ik begrijp jet reactie, maar ze is offtopic. Als je even ziet, staat er ook geen komma's. (syntaxis zoals print_r het zou uitspuwen) Het is overigens een voorbeeld, geen echte code.
Ik vind het overigs persoonlijk heel mooi om met xml te werken, daarmee kan je ook heel krachtig werken. (Maar ik heb ook een erg grote liefde voor xml.)
Kan ik inkomen, maar ik ga deze parser niet los gebruiken. Komt in een groter project. En als ik dan met XML dien te werken, maag ik het mezelf alleen maar moeilijker.
Ik ben zonet weer aan het knutselen gegaan. Ik begrijp toch echter niet zo goed deze functie.
Ben ik werkelijk verplicht de functie "te voederen" met array($this, ...)?
Ik zie niet zo in hoe dit op een nettere manier kan. Of is dit naar jullie mening wel net?
Ik vind dat wel netjes hoor, dat je een methode van het huidige object kunt aanreiken als callback. Dat dat dan als array moet, okee.
@Bas, niet de array is het probleem, maar ik vind de hele "$this" meegeven nogal vaag.
Het gaat om de combinatie van functienaam en object-waarin-de-functie-leeft. Vraag ik mij uit het hoofd even af of je een statische methode ook op die manier aanroept... ohnee dat gaat met klassenaam natuurlijk ipv $this