8792 sujets

Développement web côté serveur, CMS

Pages :
Bonjour,

Je cherche à créer un petit moteur de templates qui lit un fichier externe. Avec les regexps, je parviens à détecter des templates qui se terminent par une fin de ligne ("\n"). Mais si un template est en fin de fichier, il n'est pas détecté. Y a-t-il un code pour détecter la fin de fichier ?

Merci

BMR
Modifié par marabbeh (26 Oct 2006 - 09:47)
Voici par exemple un formulaire de contact :

[T:form method=post]
<div class="ligne">
[T:form-text name=nom label=label_nom format=name css=text-field /]
</div>
<div class="ligne">
[T:form-text name=email label=label_email format=email css=text-field /]
</div>
<div class="ligne">
[T:form-textarea name=comment label=label_comment format=no_htmljs lim=0,2000 css=text-field /]
</div>
<div class="boutons">
[T:form-submit text=bouton_ok name=envoi css=bouton /]
[T:form-reset text=bouton_annule css=bouton /]
</div>
[T:/form]

Modifié par marabbeh (23 Oct 2006 - 15:23)
Administrateur
Hello,

Merci de bien vouloir suivre la règle communément admise d'entourer tout code par les balises [ code] appropriées Smiley cligne
marabbeh a écrit :
Voici par exemple un formulaire de contact :

[T:form method=post]
[...]

Et si ta regexp récupérait juste tout ce qui ressemble à [T: ... ] ?
OK Raphaël. C'est ce que je me suis dit après avoir envoyé le post...

Je teste la fin de ligne afin qu'on puisse éventuellement mettre des crochets dans les valeurs des attributs :


[T:form-text name=xxx label=label entre [crochets] /]


(il y a des [ ] autour de "crochets" mais ça ne sort pas)

Evidemment ce test de fin de ligne interdit de mettre du code HTML derrière le code template dans la même ligne... Mais bon, faut choisir...

Pour la fin de fichier, je rajoute systématiquement une ligne vide en fin de fichier. Mais s'il y avait un test de fin de fichier ce serait mieux.

Le fait d'en discuter, me fait penser à une autre solution, cad de lire le template ligne par ligne, ce qui résoudrait les contraintes indiquées ci-dessus. Ce que je ne fais pas pour l'instant, car je lis le template d'un bloc et applique la regexp globalement, pour aller plus vite. Il faudrait que je fasse des tests de rapidité...
Modifié par marabbeh (23 Oct 2006 - 15:37)
a écrit :

Je teste la fin de ligne afin qu'on puisse éventuellement mettre des crochets dans les valeurs des attributs :

C'est parfaitement faisable,a vec la regexp suivante :
\[T:.*\]
Comem ça, tu peux cooler du code HTML avant et/ou après l'indication de template, et utiliser des crochets dans les valeurs d'attributs du template.

Le seul moment où ça risque de bugger, c'est avec une ligne comme :
[T:abcd efg=hij Smiley klm nop rst=uvwx][T:yz abc=def ghi=jk Smiley lmn opq rst=uvwxyz]
J'ai testé l'analyse du template ligne par ligne, au lieu de faire tout en bloc, finalement c'est un poil plus rapide (-25%), car le code est plus court.

Donc en principe je n'ai plus besoin de tester la fin de ligne dans la regexp avec un "\n".

A Quentinc : tu ne réponds pas à la question que tu as mise en citation Smiley smile .
Mon dilemme est :
- j'autorise les crochets à l'intérieur d'un [T:...], donc je ne peux avoir qu'un [T:...] par ligne, mais avec éventuellement du texte/html (par exemple Spip, entre autres, utilise aussi une syntaxe à crochets, d'où l'intérêt de les autoriser)
- j'interdis les crochets à l'intérieur d'un [T:...] et je peux avoir plusieurs templates par ligne, ainsi que du texte/html.

Je préfère le 1er cas, et ça rend le template plus lisible. Dans une partie de l'appli, j'utilise ce moteur de template à des fins internes, et c'est la 2e solution que j'utiliserai, car j'ai la maîtrise du contenu du template.

A moins qu'il y ait des options de recherche ou une gestion fine des sous-masques de regexp qui pourrait concilier les deux...

Réédition : en fait une regexp comme :

\[(\/)?T:.*\]


fonctionne sans option de recherche (donc greedy je suppose) avec un code comme :

<div>[T:abcd efg=hij rst=uvwx]</div><div>[T:yz abc=def ghi=[jklmn] rst=uvwxyz]</div>


sur la même ligne.

Tu avais raison Quentinc ! Pourquoi chercher la complication ?
Modifié par marabbeh (24 Oct 2006 - 11:42)
Bon, c'est un super exercice en fait, j'ai fait ça :
<?php

$pouet =
'[T:form method=post tagada=[pou_et]]
<div class="ligne">
[T:form-text name=nom label=label_nom format=name css=text-field /]
</div>
<div class="ligne">
[T:form-text name=email label=label_email format=email css=text-field /]
</div>
<div class="ligne">
[T:form-textarea name=comment label=[label_comment] format=no_htmljs lim=0,2000 css=text-field /]
</div>
<div class="boutons">
[T:form-submit text=[bouton_ok] name=envoi css=bouton /][T:form-reset text=bouton_annule css=bouton /]
</div>
[T:/form]';

$resultat = array();

if(preg_match_all('#\[T: (?: (?:/([a-zA-Z]*-?[a-zA-Z]*))|(?: ([a-zA-Z]+-?[a-zA-Z]*)((?:\s.+?=(?: (?:\[.+?\])|(?:.+?))(?!\s/))*)(?:\s/)?))\]#x', $pouet, $resultat, PREG_SET_ORDER)) {

    foreach($resultat as $element) {

        // Si il y a une liste d'arguments
        if(isset($element[3])) {

            // Si la liste de termine par /, c'est une balise autofermante
            if(substr($element[3], -1) == '/') {

                // On vire le slash final
                $element[3] = substr($element[3], 0, strlen($element[3]) - 1);
                $autoFermante = true;
            } else {
                $autoFermante = false;
            }

            $element[3] = trim($element[3]);

            // Récupération des arguments
            $element[3] = explode(' ', $element[3]);
            $arguments = array();
            foreach($element[3] as $arg) {

                $argArray = explode('=', $arg);
                $arguments[$argArray[0]] = $argArray[1];
            }


            echo '<br />Balise <b>', $element[2], '</b>', ($autoFermante ? ' auto-fermante' : ' ouvrante'), '<br />';
            echo '<pre>', print_r($arguments, true), '</pre>';
        } else {

            echo '<br />Balise <b>', $element[1], '</b> fermante';
        }
    }
}

Modifié par FlorentG (24 Oct 2006 - 11:34)
Merci je vais tester. J'espère que mon problème ne vous distrait pas trop de votre travail... Smiley confus

Mais ça marche bien ! Même en mettant tout le template dans la même ligne. Par contre, un petit souci, lorsqu'il y a un espace dans une valeur d'attribut, celle-ci est tronquée. A cause de l'option /x ? Je vais décortiquer ta regexp.
Modifié par marabbeh (24 Oct 2006 - 12:09)
Comment dire... C'est presque parfois nécessaire, pour apprendre : la meilleur façon d'apprendre, c'est d'enseigner et d'essayer. Alors du coup ça me permet de revoir les bases, ou d'être confronté à un problème jamais vu qui pourrait peut-être me servir par la suite.

Là par exemple, ça m'a permis de revoir un peu les expressions régulières, et un peu le parsing de texte. Chose que je n'avait jamais réellement fait Smiley smile

Bon, le code n'est pas le plus joli du monde, mais ça marchouille à peu-près Smiley lol
Ben moi j'utilise assez souvent les regexps, mais je suis souvent surpris, dans le bon sens ou dans le mauvais sens, de leur comportement. C'est que je les maîtrise pas à 100%, loin s'en faut... Smiley decu
Je pense que les valeurs d'attributs comportant des espaces sont tronquées à cause de l'explode...
Si tu décides de changer un peu la syntaxe en encadreant les valeurs de tes arguments avec des guillemets ou un quelconque autre délimiteur (à ta convenance !), il existe une solution pour récupérer des attributs avec espace :


$element[3] = preg_replace_callback('#"(.*?)"#', 
create_function('$match', '
return str_replace(" ", chr(160), $match[1]);
'), $element[3]);

Juste avant l'explode. Et ensuite, évidemment, faire la reconversion inverse une fois les arguments explodés.

Je sais pas si ça pourrait servir, mais j'avais écrit un moment donné une fonction qui renvoyait l'index d'un crochet fermant correspondant à un crochet ouvrant...

Je ne sais pas pourquoi ni comment mais je pense que la méga-regexp proposée ci-dessus doit pouvoir se simplifier... en la parcourant rapidement, j'ai l'impression qu'elle se répète pas mal ... c'est quoi le but de cette regexp exactement ?

JE vois plutôt les choses comme :
\[T:\s*[-a-zA-Z]+(?: [-a-zA-Z_]+(?:=(?:".*?"|[-a-zA-Z0-9_]+))?)*(?: /)?\]
Modifié par QuentinC (24 Oct 2006 - 19:33)
bonjour

euh il me semble que je vais faire un beau hors-sujet, mais la première question est : comment détecter la fin d'un fichier ?
c'est très simple.
tu ouvres ton fichier avec fopen j'imagine (avec fsockopen, ca fonctionne aussi), et tu fais :
$fop = fopen('fichier.tpl');
while(!feof($fop)) { /* ... */ }

feof teste la fin du fichier, et renvoie FALSE si le pointeur est à la fin du fichier.
je pense que c'est plus simple que de mettre des syntaxes particulières, visibles par expreg :s (ce qui est plus lourd)

PS : ca fesait 8semaines que j'avais pas internet, et que j'ai pas posté sur alsacreations, il me fallait un message de retour Smiley lol

en espérant t'avoir aidé

doc PHP : http://fr.php.net/feof
HyWaN a écrit :
euh il me semble que je vais faire un beau hors-sujet, mais la première question est : comment détecter la fin d'un fichier ?


En effet, je craignais cette réponse, c'est pourquoi j'avais mis "regexp" dans le sujet. Smiley smile

Mais toutes les propositions faites rendent caduque cette recherche de la fin de fichier. Le sujet du thread est devenu qqch comme "détection de codes à crochets dans un template". Il faudrait que je puisse modifier le sujet du thread en ce sens...
Pour modifier le titre du sujet, il faut éditer ton premier post
C'est expliqué dans la charte que tu devrais avoir lue avant de poster.
J'ai pas vraiment suivi le fil, mais pour isoler les [T:....], il y a ça :
$pouet ='
[T:form method=post]

<div class="ligne">

[T:form-text name=nom label=label_nom format=name css=text-field /]

</div>

<div class="ligne">

[T:form-text name=email label=label_email format=email css=text-field /]

</div>

<div class="ligne">

[T:form-textarea name=comment label=label_comment format=no_htmljs lim=0,2000 css=text-field /]

</div>

<div class="boutons">

[T:form-submit text=bouton_ok name=envoi css=bouton /][T:form-reset text=bouton_annule css=bouton /]

</div>

[T:/form]';


$motif='`\[T:[^]]+/?\]`s';

preg_match_all($motif, $pouet, $tab);
echo '<pre>';
print_r($tab);
echo '</pre>';
Le problème c'est que là, tu interdis les crochets fermants dans la valeur des attributs. Je me trompe peut-être, mais ce n'est pas ce qui est voulu il me semble.

Au passage, tu as oublié d'échapper un crochet :
$motif='`\[T:[^\]]+/?\]`s';
QuentinC a écrit :
Au passage, tu as oublié d'échapper un crochet

Absolument pas, la regex est parfaitement correcte en l'état !
$motif='`\[T:[^]]+/?\]`s';
QuentinC a écrit :
Pour modifier le titre du sujet, il faut éditer ton premier post
C'est expliqué dans la charte que tu devrais avoir lue avant de poster.


C'est fait. Il y a quelques mois, j'avais aussi voulu modifier le titre et personne ne m'avais dit comment faire. Evidemment il fallait lire la charte... Smiley smile
Pages :