13Fermer15
ZephLe 13/12/2016 à 22:30
Meowcate (./13) :
Je ne pense pas que pour ta façon de structurer le bbcode, tout en voulant assurer une rétro-compatibilité, tu puisses te passer d'un cas particulier.
Je me trompe peut-être mais j'espère encore que si grin
Meowcate (./13) :
Dans le doute, tu peux bien aller voir du bbcode open-source comme sur phpBB pour voir comment ils résolvent ce genre de problème.
J'ai regardé pas mal de solutions de balises dans des projets open-source, mais c'est souvent assez rudimentaire par rapport à ce que propose yAronet (et ça ne date pas de moi, le jeu de balises n'a quasiment pas changé depuis que je m'en occupe) : pas de balises autres que ouverture/fermeture, pas de séquence d'échappement, génération de code HTML invalide dès que les balises sont mal utilisées, ou bien balises non reconnues quand elles sont entrecroisées, etc. Le code de phpBB traite les balises en 25 passes d'analyse sur la chaine et du code custom (y compris des requêtes SQL !) pour à peu près toutes les balises, ce que j'aimerais doublement éviter :/

Voilà donc le pseudo-code de traitement des balises qui correspond au post ./1, en espérant que ce soit un peu plus clair que ma tentative d'explication :function remplace_balises(texte) { candidats = []; // Liste des séquences encore incomplètes en cours de construction sequences = []; // Liste des séquences complètes (qui possèdent une balise ouvrante, une fermante et éventuellement des balises intermédiaires entre les deux) // Première passe : repérage des séquences de balises foreach (balise in trouve_balises(texte)) // Simple recherche lexicale de toutes les balises, ordonnées par offset, avec une grosse regexp ou équivalent { if (balise.est_ouvrante) // Balise ouvrante : démarre peut-être une nouvelle séquence { sequence = new Sequence(); sequence.append(balise); candidats.ajoute(sequence); // L'ordre des séquences candidates suit celui des balises ouvrantes, elles sont donc naturellement triées par l'index de leur première balise } else // Balise non-ouvrante : peut continuer n'importe quelle séquence qui contient des balises compatibles (par exemple [*] est compatible avec [table]) { foreach (candidat in candidats) { if (candidat.est_compatible_avec(balise)) { candidat.ajoute(balise); if (balise.est_fermante) // On vient d'ajouter une balise fermante à une séquence, elle est donc complète { candidats.supprime(candidat); // Supprimer la séquence actuelle des candidats potentiels sequences.ajoute(candidat); // Ajouter la séquence actuelle aux séquences complètes annuler_balises_superposees(candidats, candidat); // Supprimer des candidats toutes les balises faisant partie de la séquence actuelle, puisqu'elles sont utilisées et ne peuvent plus faire partie d'une autre séquence break; // Notre balise fermante vient de compléter une séquence, pas besoin de chercher plus loin } } } } } // Deuxième passe : suppression des séquences complètes foreach (sequence in sequences) { foreach (balise in sequence) texte.supprime(balise.offset, balise.length); // Incorrect : les offets deviennent potentiellement invalides dès qu'on commence à changer le texte, mais en pratique il suffit de les corriger ou de les retirer en partant par la fin pour contourner ce souci } return (texte, sequences); // Récupération du texte brut (sans les balises) d'un côté, et de la liste des balises groupées par séquence d'un autre }