Conversions de syntaxes Wiki
←
→
Transcription du contenu de la page
Si votre navigateur ne rend pas la page correctement, lisez s'il vous plaît le contenu de la page ci-dessous
Conversion de syntaxes Wiki lUNIVERSITE LILLE 3 Année 2008-2009 Travail d’Etudes et de Recherche Conversions de syntaxes Wiki MIASHS M1 : Informatique et Document Version 1.0 Auteurs : MANTEL Julien Enseignant responsable: TOMMASI Marc UNIVERSITE CHARLES-DE-GAULLE - LILLE 3 Domaine universitaire du "Pont de Bois" rue du Barreau - BP 60149 59653 Villeneuve d'Ascq Cedex Mantel Page 1 sur 29
Conversion de syntaxes Wiki Remerciements Je tiens à adresser mes sincères remerciements : A Monsieur Marc TOMMASI, membre du Grappa, et enseignant-chercheur a l’Université de Lille3, notamment dans la spécialité Informatique et Document, de la mention MIASHS (mathématiques informatiques sciences humaines et sociales) du master Sciences Humaines et Sociales, qui, m’a permis de réaliser ce travail et qui, par ses nombreux conseils, m’a permis de le réaliser. A Monsieur Jérémie Mary, membre du Grappa, enseignant-chercheur et responsable du Master MIASHS spécialité Informatique et Document. Enfin, je tenais à remercier ceux qui ont participé de prés ou de loin a ce travail, notamment Johan Dufour, qui m’ont épaulé et ou participer a la relecture de ce document. Mantel Page 2 sur 29
Conversion de syntaxes Wiki Contrôle du document Historique des versions Date Version Auteurs Principales modifications 16 Juin 1.0 Mantel Création et rédaction du document Distribution Aux auteurs Au responsable enseignant Etat Travail Terminé Validé Archivage Sécurité et confidentialité Copyright aux auteurs. A diffusion limitée : au responsable enseignant, aux auteurs Responsabilité Ne s’applique pas Note sur cette édition Aucun commentaire Mantel Page 3 sur 29
Conversion de syntaxes Wiki Sommaire Remerciements .......................................................................................................... 2 Introduction................................................................................................................. 5 I) Présentation de l’Inria et des syntaxes Wiki. ........................................................... 6 Présentation de l’Inria.......................................................................................... 6 reStructuredText.................................................................................................. 7 TWiki Markup ...................................................................................................... 9 L’initiative WikiCréole ........................................................................................ 10 Contexte et problèmatique........................................................................................ 11 II) Outils existants, et méthodes de conversions ...................................................... 11 Introduction........................................................................................................ 11 Docutils.............................................................................................................. 11 HtmlToTWiki Converter ..................................................................................... 11 Méthode par approche arborescente................................................................. 12 Technique ligne a ligne...................................................................................... 15 Les expressions régulières................................................................................ 16 III) Mise en œuvre .................................................................................................... 17 Introduction........................................................................................................ 17 Technique utilisée.............................................................................................. 17 Gestion des fichiers ........................................................................................... 17 Ouverture et lecture d’un fichier, et choix de conversion ................................... 18 Création du fichier final...................................................................................... 19 Fonction de conversion RST vers WikiCréole (parser)...................................... 20 Approches arborescente ................................................................................... 22 Conclusion................................................................................................................ 23 Mantel Page 4 sur 29
Conversion de syntaxes Wiki Introduction Ce document est le rapport de synthèse du travail d’études et de recherches (TER) de 6 semaines que j’ai effectué du 12 Mai au 23 Juin 2009, dans le cadre de la première année du Master MIASHS Informatique et Document, à l’Université Charles-De-Gaulle, Lille 3. Ce TER avait comme objectif de vérifier les connaissances que j’ai acquis au cours de cette première année, ainsi que de me préparer au monde du travail. Ces 6 semaines ont eu pour but la compréhension des méthodes de conversions de Wiki, ainsi que la réalisation d’un programme de conversion. Le sujet consistait en une compréhension des différentes syntaxes de Wiki, notamment Twiki et le ReStructured Text (RST), une étude des outils et des méthodes de conversion existantes (Docutils, conversion en arborescence, ou ligne par ligne), et en une mise en œuvre de ces techniques, à travers la programmation d’une application de conversion, en Python. Ce rapport montrera d’abord une présentation rapide de l’Inria, et une présentation détaillée des syntaxes Wiki étudiées. Nous ferons ensuite une analyse des techniques existantes, avant de présenter le travail de programmation effectué. Différents aspects du travail seront aussi montrés, notamment, une réflexion sur les techniques de conversion, et les problèmes rencontrés lors du développement. Mantel Page 5 sur 29
Conversion de syntaxes Wiki I) Présentation de l’Inria et des syntaxes Wiki. Présentation de l’Inria 1) L’inria en bref L'Institut national de recherche en informatique et en automatique (INRIA) est un organisme public civil de recherche français créé le 3 janvier 1967 suite au lancement du Plan Calcul. L’Inria a pour vocation d'entreprendre des recherches fondamentales et appliquées dans les domaines des sciences et technologies de l'information et de la communication (STIC). L'institut assure également un fort transfert de technologie en accordant une grande attention à la formation par la recherche, à la diffusion de l'information scientifique et technique, au développement, à l'expertise et à la participation à des programmes internationaux. 2) Quelques Chiffres : Ressources budgétaires (janvier 2008) : • Budget total : 186 Millions d’euros HT • Ressources propres : 1/5 Ressources humaines (janvier 2008) • 3 800 personnes, dont 2 100 rémunérées par l'INRIA répartis dans 8 centres de recherche. • 2 800 scientifiques, dont 1 300 chercheurs et enseignants- chercheurs, 1 000 doctorants, et 500 post doctorants et contractuels Activités scientifiques (janvier 2008) • 150 équipes-projets de recherche • 4 000 publications scientifiques • 24 conférences internationales organisées ou co-organisées par l'INRIA ayant mobilisé 2 500 participants dont 1 700 étrangers • 14 300 heures d'enseignement Relations industrielles (janvier 2008) • 790 contrats de recherche actifs • 230 brevets actifs • 80 logiciels déposés à l'Agence pour la Protection des Programmes • 89 sociétés de technologie issues de l'INRIA, depuis Ilog, aujourd'hui cotée au Nasdaq, jusqu'aux 9 dernières créées en 2007. Mantel Page 6 sur 29
Conversion de syntaxes Wiki reStructuredText 1) Présentation Le reStructuredText est un langage très léger d’écriture de Wiki. Son nom signifie : "revised, reworked, and reinterpreted StructuredText", et est parfois abrégé RST. Le parser (analyseur syntaxique) est intégré dans la bibliothèque Docutils (http://docutils.sourceforge.net/index.html), cette dernière étant écrite en langage Python. A noter que d’autres parsers sont disponibles, et qu’ils sont disponibles pour d’autres langages que Python. Le reStructuredText est donc utilisé dans la création de documentations techniques, cela donc peut être une documentation sous forme de Wiki. Une documentation complète du RST est disponible sur le site http://docutils.sourceforge.net/rst.html et une rapide introduction au langage est disponible sur le site suivant : http://commandline.org.uk/python/introduction- restructuredtext/ Nous pouvons déjà remarquer quelques exemples de syntaxes propres au RST. Ces exemples se focalisent sur des exemples un peu plus complexes que les simples « soulignement, mise en emphase… » 2) Quelques règles de formatages • Formatage de caractères : *texte en italique* **texte en gras** • Titres, sous-titres: Titre ===== Sous-titre ---------- Le nombre de caractères au dessus et au dessous du (sous-)titre doit être égal au nombre de caractères de la chaîne à traiter. • Des listes : - Une liste a puce - 2eme item - Un sous item 1) Une liste numérotée 2) Second item a) Sous item i) Sous sous item 3) Troisième item # Item auto-incrémenté (L’indentation définit le niveau de l’item dans la liste) Mantel Page 7 sur 29
Conversion de syntaxes Wiki • Des liens nommés : A sentence with links to Wikipedia_ and the `Linux kernel archive`_. .. _Wikipedia: http://www.wikipedia.org/ .. _Linux kernel archive: http://www.kernel.org/ (Ce sont les underscores qui définissent les mots sur lequel le lien sera activé). • Liens “anonymes” : Another sentence with an `anonymous link to the Python website`__. __ http://www.python.org/ • Le RST permet aussi d’afficher des « directives » semblables à d’autres langages et qui permettent des fonctions un peu plus avancées, telles que l’affichage d’images ou encore de code. Exemples : .. image:: \http://commandline.org.uk/images/whokilledtux.png Permet d’afficher l’image fournie en URL. .. sourcecode:: python import os for i in os.uname(): print i Permet l’affichage de ce code dans un cadre type « code ». Mantel Page 8 sur 29
Conversion de syntaxes Wiki TWiki Markup 1) Présentation TWiki est un logiciel moteur de Wiki, développé en Perl, qui fourni une plateforme de travail collaboratif. Il peut être utilisé comme un espace de développement, système d'administration de documents ou de personnel. Les développeurs peuvent ajouter des fonctionnalités grâce à des extensions et des scripts TWiki. La communauté autour de ce projet Open Source est donc importante. Il est à noter qu’il existe un markup pour TWiki, dont nous verrons quelques syntaxes, mais il n’est pas indispensable de la connaître pour écrire du contenu : un éditeur WYSIWYG est intégré au logiciel, ce qui favorisera son utilisation auprès des néophytes. Plus d’informations sont disponibles sur le site officiel (http://twiki.org/), et les règles de formatage sont disponibles à l’adresse suivante : http://twiki.org/cgi- bin/view/TWiki/TextFormattingRules 2) Quelques règles de formatage • Formatages des caractères _texte en italique_ *texte en gras* • Titre, sous-titres ---++ Titre niveau 1 ---+++ Titre niveau 2 • Listes * Liste a puce * Deuxième item 1. Liste numérotée 1. Deuxième item (sera numéroté 2, le 1. note l’appartenance à la liste) 1. Sous item On notera qu’on peut aussi utiliser une incrémentation en lettres ou en chiffres romains. • Liens [[Url du lien]] [[Url du lien][libellé du lien]] Mantel Page 9 sur 29
Conversion de syntaxes Wiki On peut déjà remarquer ici les différences entre la syntaxe RST et Twiki : il n’y a pas beaucoup de syntaxes communes. Cependant, dans un souci de rendre les syntaxes compatibles entres elles, des initiatives d’universalisation des syntaxes Wiki sont apparues, et notamment l’initiative WikiCréole. L’initiative WikiCréole 1) Présentation Le projet WikiCréole a été crée dans le but d’uniformiser les différents langages des Wiki, ce qui permet une meilleure compréhension pour les novices. Le projet Créole 1.0 a été achevé le 4 Juillet 2007, et officialise les premières spécifications de l’initiative. http://www.wikicreole.org/wiki/Creole1.0 2) Quelques règles de formatage • Formatages de caractères //Texte en italique// *Texte en gras* • En-tête : = Titre niveau 1 = == Titre niveau 2 == === Titre niveau 3 === • Listes : * Liste a puce ** Niveau 2 * Niveau 1 # Liste auto incrémentée ## Sous item auto incrémentée # Autre item niveau 1 • Liens : [[link]] [[MyBigPage|Go to my page]] [[http://www.wikicreole.org/]] [[http://www.wikicreole.org/|Visit the WikiCreole website]] On remarquera donc quelques similitudes avec le TWiki, notamment pour les syntaxes des listes à puces ou des liens. Cependant, nombre des syntaxes sont très différentes les unes des autres, ce qui nous amène à notre problématique. Mantel Page 10 sur 29
Conversion de syntaxes Wiki Contexte et problématique L’Inria souhaite migrer ses structures TWiki vers le reStructuredText, pour pouvoir l’intégrer dans son système Plone. Cependant, les deux syntaxes étant très différentes l’une de l’autre, concevoir un programme pouvant convertir toutes ces syntaxes n’est pas forcément évident. Existe-t-il donc des outils, ou des programmes capables de traiter une partie du problème, et pouvant aussi donner des indications sur les méthodes de conversion existantes ? II) Outils existants, et méthodes de conversions Introduction Il existe des outils et des programmes permettant certaines conversions, notamment des conversions vers l’HTML, XSLT ou autres. Cependant, nous allons intéresser à 2 outils. Le premier étant le parser (convertisseur) présent dans la bibliothèque Docutils, bibliothèque développée en python et contenant la syntaxe reStructuredText. Le deuxième, étant le programme HtmlToTWiki Converter, écrit en Perl, pour l’environnement TWiki, et qui, comme son nom l’indique, converti l’HTML en syntaxe TWiki. Ces 2 programmes seront étudiés afin de ressortir leurs méthodes de conversion, et nous décrirons ces méthodes. Docutils Docutils est donc une bibliothèque développée en Python, permettant le traitement de documents HTML, XML ou encore LaTeX. Docutils propose aussi divers outils, et donc celui qui nous intéressera le plus, le parser permettant de convertir le reStructuredText vers d’autres formats. L’ensemble des outils est téléchargeable sur la page web de l’outil http://docutils.sourceforge.net/ , le package docutils-0.5.tar.gz ainsi téléchargé contient tous les fichiers des bibliothèques. Il existe donc plusieurs programmes de conversion au sein de ce package, notamment les programmes rst2html.py, rst2xml.py, rst2latex.py etc, convertissant donc chacun, le RST vers un format choisi. Cependant, ce ne sont pas ces fichiers qui font la conversion. Cette tache est effectuée en 4 temps par différentes fonctions, et ces différentes étapes constituent la conversion par approche arborescente. Nous allons détailler cette technique et les différentes étapes la composant par la suite HtmlToTWiki Converter Ce programme est une petite application développée en Java, et existante aussi en Perl, permettant de coller son document HTML dans une fenêtre et retournant le résultat en syntaxe TWiki. Le parser de la version en Perl, utilise une autre technique que celui de Docutils. La technique employée est celle de la conversion ligne à ligne. Mantel Page 11 sur 29
Conversion de syntaxes Wiki Méthode par approche arborescente La méthode de conversion par arborescence se décompose en 4 étapes : la lecture du document, l’analyse (parsing), la transformation, et enfin l’écriture du document. La finalité de cette méthode est bien sur d’obtenir une conversion complète et valide. Il est important de noter que pendant l’analyse, un document intermédiaire, en arbre donc, est crée. On peut symboliser schématiquement cette représentation comme ci-dessous. Document Document initial Lecture Analyse Transformation Ecriture final Création d’un document en arbre Schématisation de la methode arborescente Lecture Le programme (par défaut avec Docutils, il s’agit de docutils/readers/standalone.py) récupère le document en entrée et le garde en mémoire pour la suite du traitement. Analyse C’est ici que le parser intervient. Par défaut il se trouve dans /docutils/parsers/__init__.py . C’est donc lors de cette étape qu’est crée un fichier intermédiaire. On peut avoir un aperçu d’un tel fichier en utilisant la fonction du fichier quicktest.py . Avec un fichier « test.txt » écrit en RST comme ci-dessous : My *favorite* language is Python_. .. _Python: http://www.python.org/ On obtient en sortie, fichier comme celui-ci : My favorite language is Python . Mantel Page 12 sur 29
Conversion de syntaxes Wiki On remarque directement que cette structure arborescente, ressemble très fortement à la structure d’un document XML, ce qui nous amènera à poser une petite réflexion à ce sujet. On notera par ailleurs que le parser, en l’état, permet de transformer certaines syntaxes comme l’emphasis, ou les paragraphes simples. Transformation Cette étape va transformer les éléments qui ne l’ont pas été durant la phase précédente. Cela consiste donc en une succession de traitements, que le système effectuera lorsqu’il aura repéré une balise appropriée. On pourra donc traiter les liens hypertextes, les tables de matières (donc les listes, ou tableaux), les notes de références, etc etc. Dans notre exemple ci dessus, on constate que l’élément « reference » Python, n’a pas son adresse en attribut. L’étape de transformation va donc, entre autres, traiter ce problème, après avoir identifié cette référence. Le fichier arborescent obtenu peut être visualisé grâce à la fonction « rst2pseudoxml.py », qui porte bien son nom. (A noter qu’on pourra obtenir du vrai xml avec « rst2xml.py » My favorite language is Python . On remarque donc l’ajout de l’url en attribut de l’élément « reference ». Ecriture Cette dernière fonction va tout simplement transformer nos éléments pseudo XML en éléments valides du langage de sortie choisi. Par exemple, toujours avec notre fichier ci-dessus, la fonction de transformation en HTML « rst2html.py » donnera en sortie le fichier suivant : Mantel Page 13 sur 29
Conversion de syntaxes Wiki My favorite language is Python. Avantages, inconvénients La méthode en arborescence présente plusieurs avantages, dont le principal est de pouvoir utiliser le document pseudo-XML, pour transformer le document. En effet, il suffirait de transformer les « balises » éléments du fichier pseudo-XML vers la syntaxe des éléments du format de sortie choisi, comme dans notre exemple ci-dessus, avec une sortie en HTML. Le parser (étape d’analyse) n’a donc, dans l’absolu, pas besoin d’être modifié. Pour avoir un nouveau format de conversion, il faudrait donc ajouter une nouvelle fonction d’écriture, contenant les transformations du format désiré. Par contre, on notera que pour obtenir une transformation vers un format, il faudra forcément passer par les 4 étapes et donc ceci peut engendrer du calcul supplémentaire, pas forcément nécessaire lorsque la transformation désirée est simple : imaginons une transformation XML vers XHTML en utilisant ce procédé, il faudrait repasser l’XML vers un pseudo XML pour ensuite le repasser vers de l’XTML…qui est très semblable a l’XML au final. Réflexion sur l’aspect XML Nous avons vu que cette méthode créé une représentation en pseudo-XML, c'est-à-dire une représentation en arbre/élément. On peut donc en déduire que l’XML, est une représentation de choix pour la représentation de tous les documents. En effet, ce choix de prédilection montre aussi la facilité d’écriture et de lecture de l’XML, et permet donc facilement la transformation des éléments vers de nouvelles syntaxes et langages, tel que l’HTML, l’XSLT, LaTeX, etc etc. Mantel Page 14 sur 29
Conversion de syntaxes Wiki Technique ligne a ligne Contrairement à la technique par arborescence, cette deuxième technique n’utilise pas de format intermédiaire. Le programme « Html2TWiki » montre en effet que le fichier en entrée est lu (les lignes des fichiers sont gardées en mémoires), et un traitement a base d’expressions régulières, est appliqué sur chaque ligne. La transformation est aussitôt faite sur la ligne grâce à cette méthode. On peut représenter un tel algorithme par ce schéma : Ouverture du fichier Lecture du fichier Lecture d’une ligne Traitement des expressions régulières Si non EOF Transformation de la ligne Ecriture de la ligne Fermeture fichier Algorithme ligne à ligne Avantages, inconvénients Le principal inconvénient de cette technique, est qu’il faut évidemment coder toutes les transformations par les expressions régulières pour une conversion donnée. Un tel programme est donc difficile à faire évoluer. Par ailleurs, travailler sur les expressions régulières est difficile et parfois rebutant, les optimisations sont coûteuses. Cependant, on notera que le temps de calcul pourra être réduit, car il n’y a pas de fichier intermédiaire en pseudo-XML. Mantel Page 15 sur 29
Conversion de syntaxes Wiki Les expressions régulières Les expressions régulières sont des chaînes de caractères décrivant un motif, motif pouvant être utilisé, repéré ou modifié dans d’autres chaînes de caractères : tout traitement automatisé peut donc être effectué grâce au repérage du motif dans une chaîne. Le bon exemple pour montrer les principes de base des expressions régulières, est la suite de mots : « ex-équo, ex-equo, ex-aequo et ex-æquo ». Cette suite de mot peut-être représentée par le motif suivant : « ex- (a?e|æ|é)quo ». On remarquera que l’on peut grouper certains caractères (avec les parenthèses), noter une quantification (« * » signifie « 0 ou plusieurs fois », « + » signifie « au moins 1 fois », et « ? » signifie « 0 ou 1 fois »), l’alternative (avec « | ») A noter que, dépendant du langage employé, des extensions sont possibles. En Python, langage qui servira à coder notre application, on notera les caractères : « […] » : Spécifie des classes de caractères ou des intervalles. « . » : Remplacement de n’importe quel caractères « \t » : Tabulation « ^ » : Signifie le début de la ligne Par ailleurs, pour spécifier qu’un caractère doit être repéré, et n’est pas un caractère spécial d’un motif, il faut utiliser le caractère « \ », comme c’est le cas pour la tabulation. Les expressions régulières en Python sont gérées et traitées grâce à la bibliothèque « re » (pour « Regular Expressions »). Nous verrons dans notre mise en œuvre, les fonctions de cette bibliothèque utilisées (notamment « re.match », « re.sub » et « re.compile ») Mantel Page 16 sur 29
Conversion de syntaxes Wiki III) Mise en œuvre Introduction Comme précisé dans le contexte du TER, l’un des objectif de celui-ci était la création d’une application pouvant convertir des syntaxes Wiki, et notamment le passage de TWiki vers reStructuredText. La conversion inverse était elle aussi envisagée. Le choix du langage pour une telle application s’est donc porté vers Python. A noter que certaines bibliothèques ont été utilisées, notamment donc, la bibliothèque « re » (Regular Expressions), ainsi que la bibliothèque « os » pour la gestion des fichiers. Dans cette partie nous verrons donc plusieurs aspects techniques de la réalisation de l’application, nommée Wiki2All.py, avec pour chaque aspect, les problèmes rencontrés. Technique utilisée A l’origine, le développement s’est dirigé vers la méthode ligne par ligne en utilisant les expressions régulières sur chacune des lignes des fichiers. La conversion passerait directement de RST vers TWiki et inversement. Cependant, après avoir étudié l’initiative d’universalisation WikiCréole, il semblait intéressant de pouvoir gérer cette syntaxe aussi. L’idée d’utiliser la syntaxe WikiCréole comme syntaxe intermédiaire est donc apparue, modifiant la technique ligne à ligne en une technique « hybride » : une technique ligne à ligne mais avec format intermédiaire (mais qui n’est pas apparentée a l’XML). Gestion des fichiers Explications Cette partie a été très vite implémentée au tout début du développement et n’a pas été modifiée par la suite. Elle consiste à lister les différents fichiers compatibles dans le dossier courant du fichier Wiki2All.py. Ces fichiers portent les extensions « .rst », « .cre », ou « .twi ». Ils ne correspondent à aucune extension existante, ce sont simplement des fichiers textes dont l’extension est choisie en fonction du langage utilisé. La fonction « listdir » de la bibliothèque « os » a été utilisée pour lister les fichiers. Quelques tests sont nécessaires afin de ne pas lister les dossiers et fichiers cachés, ainsi que les fichiers dont le format n’est pas souhaité. Au final on obtient un objet liste contenant les noms des fichiers compatibles. from os import listdir #Déclaration des extensions de fichiers valides pour la création de la liste de fichier valides a l'ouverture format1=".rst" format2=".twi" format3=".cre" #Création de la liste de fichiers valides def listedefichiervalides(): global listfichier Mantel Page 17 sur 29
Conversion de syntaxes Wiki #on crée une premier liste pour obtenir les noms de fichiers du dossier courant (meme les cachés et les temporaires) listfichier = listdir(".") i=0 #le While est utilisé, car lors d'une suppression il faut rester sur le meme indice pour retester le nouveau nom. Ceci n'est pas possible avec un for. while i < len(listfichier): print listfichier[i] #le gros test : on test les 4 derniers caracteres du fichier en cours. Si il ne correspond pas a un format, on le supprime de la liste. Sinon on le passe. if (listfichier[i][(len(listfichier[i])-4):(len(listfichier[i]))] != format1 and listfichier[i][(len(listfichier[i])-4):(len(listfichier[i]))] != format2 and listfichier[i][(len(listfichier[i])-4):(len(listfichier[i]))] != format3): listfichier.remove(listfichier[i]) else : i+=1 print "Liste de fichier valides disponibles :", listfichier Problèmes rencontrés La fonction telle qu’elle ne vérifie pas si les fichiers « .rst », « .cre » ou « .twi » sont correctement écrits et valides : durant tout le TER et le développement, on a admis que les documents qui seraient traités sont valides, et n’ont pas besoin de vérification syntaxiques. Ouverture et lecture d’un fichier, et choix de conversion Afin de gérer le choix du ficher et celui de la conversion, des simples boucles de type « prompt » ont été développées. Ces boucles se contentent de demander le nom de fichier à rentrer, et un numéro de choix de conversion. Des messages d’erreurs sont renvoyés si le fichier n’est pas dans la liste des fichiers valides, ou si le choix de conversion n’est pas possible, par exemple quand on souhaite convertir un fichier « .rst » en fichier « .rst », ou lorsque la conversion n’a pas été développée. #Fonction : affiche un prompt qui demandera quel fichier a traiter. def promptouvrirfichier(): #def de variables globales : lignesfic est la liste des lignes du fichiers, fic est la variable de fichier, formatfic est le format du fichier ouvert. global lignesfic global fic global formatfic #un flag qui servira au test d'ouverture d'un fichier flagfichierok=False while flagfichierok == False : prompt=raw_input("Entrez votre nom de fichier (valide) a ouvrir :") #boucle : on test si le nom de fichier est dans la liste crée précédemment. Si il est trouvé, on l'ouvre en lecture, on récupere les lignes, on passe le flag a True, et l'on récupere le format du fichier. for i in range(len(listfichier)): if listfichier[i]==prompt : fic=open(prompt,'r') lignesfic=fic.readlines() flagfichierok=True formatfic=prompt[(len(prompt)-4):(len(prompt))] break if flagfichierok==False : print "Fichier inexistant ou invalide." Mantel Page 18 sur 29
Conversion de syntaxes Wiki #Nouveau prompt qui demande quelle conversion a faire (on suppose que l'utilisateur fait des fichiers avec le contenu coincident a son extension. def promptconversion(): flagconvertok=False print "Attention : le fichier 'sortie.xxx' obtenu precedemment sera écrasé !" while flagconvertok==False : prompt=input("Entrez le numero de la conversion a faire : 1=RST (.rst), 2=Twiki (.twi), 3=Wiki Creole (.cre) : ") print formatfic if prompt==1 : if formatfic==".rst" : print "Le fichier est déja en extension RST." else : formatconvert=".rst" flagconvertok=True elif prompt==2 : if formatfic==".twi" : print "Le fichier est déja en extension Twiki." else : formatconvert=".twi" flagconvertok=True elif prompt==3 : if formatfic==".cre" : print "Le fichier est déja en extension Wiki Creole." else : formatconvert=".cre" flagconvertok=True return formatconvert Le choix de conversion sera aussi utilisé afin de renommer le fichier de sortie grâce à la variable « formatconvert ». Très important, dans la première des 2 fonctions, le fichier entré si il existe sera ouvert et ses lignes lues, et stockées en mémoire dans la variable globale « lignesfic ». Problèmes rencontrés La aussi, le programme ne tiens pas compte des syntaxes même des fichiers, puisque l’on admet les fichiers valides dans leur format. Les exceptions de validation ne sont donc pas gérées. Création du fichier final Maintenant que l’on connaît le format de fichier, la conversion désirée, et que le fichier en entrée est lu, la fonction suivante va créer un fichier de sortie vide avec l’extension désirée. Chaque ligne du fichier est envoyée à la fonction de conversion correspondante. Notons que seule la conversion RST vers WikiCréole avait été développée à ce moment. def creationfichierfinal(format): global fileout fileout=open("sortie"+format,'w') for i in range(len(lignesfic)): conversionligneRST2cre(lignesfic[i]) Mantel Page 19 sur 29
Conversion de syntaxes Wiki Fonction de conversion RST vers WikiCréole (parser) La conversion se faisant ligne à ligne, à la base, une seule fonction par type de conversion était présente (par exemple donc « conversionligneRST2cre »). Chaque ligne du fichier est reçue afin que chaque expression régulière soit testée sur cette ligne, grâce a la fonction « re.match ». Les transformations sont effectuées cas échéant, par la fonction « re.sub ». L’ensemble du code et des expressions régulières développé à ce moment du développement est fourni en annexe. Problèmes rencontrés Divers problèmes ont été rencontrés dans cette phase de développement, certainement la plus longue. La première difficulté a été de déterminer quelles sont les règles de formatages à transformer. Nous nous sommes limités donc a la conversion des caractères en gras et italiques, la conversion des listes (énumérées ou non), des titres niveau 1 et 2, des liens et si possible des tableaux. Cependant, travailler sur les expressions régulières est laborieux, et les optimisations fréquentes et/ou longues. Ce fut le cas de l’optimisation des titres niveau 1 et 2. Les titres en RST demandent d’avoir un soulignement ou un surlignement de caractères spéciaux de même taille que la chaîne à titrer, il était nécessaire de devoir conserver au moins les 2 lignes précédentes afin de comparer et d’opérer la transformation. Ceci a été réglé par l’ajout de variables globales permettant de sauvegarder les lignes précédentes. global ligneante global ligneprec global headingspotted global headingok global heading2ok lignesortie=ligne if dicoRE['Heading'].match(ligne) : if headingok or heading2ok: headingspotted=False else : headingspotted=True if len(ligne)==len(ligneprec) and ligne==ligneante : headingok=True lignesortie="== "+ligneprec fileout.write(lignesortie) elif len(ligne)==len(ligneprec) and ligne!=ligneprec : heading2ok=True lignesortie="=== "+ligneprec fileout.write(lignesortie) […] ligneante=ligneprec ligneprec=ligne Mantel Page 20 sur 29
Conversion de syntaxes Wiki A noter que cette fonction tiens compte d’une évolution que l’on évoquera par la suite, visible par l’appel « dicoRE['Heading'] ». Dans le programme principal : ligneante = "" ligneprec = "" Les variables « headingok » et « headingok2 » servent à déterminer si notre ligne en cours fait partie d’un titre niveau 1 ou 2, ce qui empêche la réécriture de lignes inutiles. Autre problème : la gestion des liens hypertextes. En effet, ceux-ci sont écrits sur 2 lignes, la première indiquant le ou les mots à rendre hypertextes, et la deuxième contenant ces mots en libellé et l’URL (voir syntaxe RST). Pour régler ce problème, je n’ai pas trouvé de meilleure solution que de lire une première fois le document afin de rechercher chaque ligne commençant par « .. _ », afin d’ajouter le libellé et l’URL dans un dictionnaire. def creationdicolinks(): global dicolinks dicolinks={} for i in range(len(lignesfic)): if re.match("^\.\. .*: ", lignesfic[i]): for j in range(len(lignesfic[i])): if lignesfic[i][j]==":" : pos2points = j break inddico = lignesfic[i][4:pos2points] valdico = lignesfic[i][pos2points+2:len(lignesfic[i])-1] dicolinks[inddico]=valdico Cependant, la manipulation de ce dictionnaire dans le parser entraîne des problèmes de repérages, qui n’ont pas été résolus : tout semble indiquer que la construction d’une chaîne est correcte cependant, le test de repérage reste non concluant. La majeure partie des problèmes restant est restée du domaine des expressions régulières, délicates à écrire et tester avec précision. Ainsi, les listes à puces, les listes numérotées, les caractères en gras ou italiques ont été traités. Cependant, les expressions s’ajoutant, très vite il devient difficile de lire le code. Sous les conseils de mon tuteur Mr. Tommasi, j’ai donc utilisé la fonction « re.compile », pour « aérer » l’affichage de mes expressions régulières. Cette fonction se charge de stocker en mémoire grâce à un dictionnaire, une expression régulière sous un nom donné, pour pouvoir réutiliser juste ce nom. Mantel Page 21 sur 29
Conversion de syntaxes Wiki Exemple d’application : def prepareRERST(): dicoRE={} dicoRE['Heading'] = re.compile("[-,=,:,~,^,_,*,+,#,]{2,}") dicoRE['Gras']= re.compile(".*\*\*.*\*\*.*") dicoRE['Italique']= re.compile(".*\*.*\*.*") dicoRE['Puce']= re.compile("^[-\+] ") dicoRE['ListeNum']= re.compile("^\t*([0-9#]+\.)* ") return dicoRE Un appel se fait de la façon suivante : dicoRE['Heading'].match(ligne) Le code devient ainsi plus clair, et il suffit d’ajouter de nouvelles entrées dans le dictionnaire, et les appeler dans les divers programmes de conversion. Cependant, par manque de temps, les autres conversions n’ont pas été implémentées. Je me suis donc penché, pendant le temps restant sur la méthode arborescente, afin de déterminer s’il était techniquement possible de la réaliser sur mon application. Approches arborescente La technique en arborescence n’est pas évidente à approcher. Il faut tout d’abord comprendre ses mécanismes de base, c'est-à-dire les 4 phases décrites précédemment. Malheureusement, le temps manquant, je ne me suis contenté que de tester ces phases, sans pouvoir en comprendre les algorithmes ou de le reproduire sur mon application. Mes tests se sont basés sur les fichiers et scripts de tests fournis dans le package Docutils et présentés précédemment, ce qui m’a permis de comprendre les fonctions. Mantel Page 22 sur 29
Conversion de syntaxes Wiki Conclusion D’un point de vue technique, ce TER m’a permis de travailler sur un aspect intéressant des technologies d’aujourd’hui, à savoir les syntaxes Wiki ainsi que les méthodes de conversions. J’ai donc pu revoir des notions vues en cours, notamment le développement Python, ainsi que le développement d’expressions régulières. D’un point de vue personnel, ce stage m’a permis de travailler en totale autonomie, comme lors de mon précédent TER l’an passé, ou j’ai du développer un produit Zope/Plone. Enfin, j’ajouterai que ce TER, m’aura évidemment permis d’acquérir de nouvelles connaissances, et d’approfondir certains aspects notamment sur les expressions régulières, et les syntaxes. Mantel Page 23 sur 29
Conversion de syntaxes Wiki Annexes Mantel Page 24 sur 29
Conversion de syntaxes Wiki Code source de Wiki2All.py #!/usr/bin/python # -*- coding: utf8 -*- from os import listdir import re #Déclaration des extensions de fichiers valides pour la création de la liste de fichier valides a l'ouverture format1=".rst" format2=".twi" format3=".cre" #Création de la liste de fichiers valides def listedefichiervalides(): global listfichier #on crée une premier liste pour obtenir les noms de fichiers du dossier courant (meme les cachés et les temporaires) listfichier = listdir(".") i=0 #le While est utilisé, car lors d'une suppression il faut rester sur le meme indice pour retester le nouveau nom. Ceci n'est pas possible avec un for. while i < len(listfichier): print listfichier[i] #le gros test : on test les 4 derniers caracteres du fichier en cours. Si il ne correspond pas a un format, on le supprime de la liste. Sinon on le passe. if (listfichier[i][(len(listfichier[i])- 4):(len(listfichier[i]))] != format1 and listfichier[i][(len(listfichier[i])-4):(len(listfichier[i]))] != format2 and listfichier[i][(len(listfichier[i])-4):(len(listfichier[i]))] != format3): listfichier.remove(listfichier[i]) else : i+=1 print "Liste de fichier valides disponibles :", listfichier #Fonction : affiche un prompt qui demandera quel fichier a traiter. def promptouvrirfichier(): #def de variables globales : lignesfic est la liste des lignes du fichiers, fic est la variable de fichier, formatfic est le format du fichier ouvert. global lignesfic global fic global formatfic #un flag qui servira au test d'ouverture d'un fichier flagfichierok=False while flagfichierok == False : prompt=raw_input("Entrez votre nom de fichier (valide) a ouvrir :") #boucle : on test si le nom de fichier est dans la liste crée précédemment. Si il est trouvé, on l'ouvre en lecture, on récupere les lignes, on passe le flag a True, et l'on récupere le format du fichier. for i in range(len(listfichier)): Mantel Page 25 sur 29
Conversion de syntaxes Wiki if listfichier[i]==prompt : fic=open(prompt,'r') lignesfic=fic.readlines() flagfichierok=True formatfic=prompt[(len(prompt)- 4):(len(prompt))] break if flagfichierok==False : print "Fichier inexistant ou invalide." #Nouveau prompt qui demande quelle conversion a faire (on suppose que l'utilisateur fait des fichiers avec le contenu coincident a son extension. def promptconversion(): flagconvertok=False print "Attention : le fichier 'sortie.xxx' obtenu precedemment sera écrasé !" while flagconvertok==False : prompt=input("Entrez le numero de la conversion a faire : 1=RST (.rst), 2=Twiki (.twi), 3=Wiki Creole (.cre) : ") print formatfic if prompt==1 : if formatfic==".rst" : print "Le fichier est déja en extension RST." else : formatconvert=".rst" flagconvertok=True elif prompt==2 : if formatfic==".twi" : print "Le fichier est déja en extension Twiki." else : formatconvert=".twi" flagconvertok=True elif prompt==3 : if formatfic==".cre" : print "Le fichier est déja en extension Wiki Creole." else : formatconvert=".cre" flagconvertok=True return formatconvert def prepareRE(): dicoRE={} dicoRE['Heading'] = re.compile("[-,=,:,~,^,_,*,+,#,]{2,}") dicoRE['Gras']= re.compile(".*\*\*.*\*\*.*") dicoRE['Italique']= re.compile(".*\*.*\*.*") dicoRE['Puce']= re.compile("^[-\+] ") dicoRE['ListeNum']= re.compile("^\t*([0-9#]+\.)* ") return dicoRE def conversionligneRST2cre(ligne): global ligneante global ligneprec global headingspotted global headingok global heading2ok global dicoliens Mantel Page 26 sur 29
Conversion de syntaxes Wiki lignesortie=ligne #heading if dicoRE['Heading'].match(ligne) : if headingok or heading2ok: headingspotted=False else : headingspotted=True if len(ligne)==len(ligneprec) and ligne==ligneante : headingok=True lignesortie="== "+ligneprec fileout.write(lignesortie) elif len(ligne)==len(ligneprec) and ligne!=ligneprec : heading2ok=True lignesortie="=== "+ligneprec fileout.write(lignesortie) if dicoRE['Italique'].re.match(ligne): #Probleme pour le caractere d'echappement \ suivi de * #if re.match("\\//", lignesortie): # lignesortie=re.sub("\\//","/*",lignesortie) #else : lignesortie=re.sub("\*", "//", ligne) #petite exception : a améliorer si possible. explications : lorsque l'on change * par //, les strong emphasis du RST passent de ** a ////. Comment matcher * et pas ** en meme temps ? En attendant, je met un match sur //// pour le changer en *. if re.match(".*////.*////.*", lignesortie) : lignesortie=re.sub("////", "*", lignesortie) if dicoRE['Gras'].re.match(ligne): lignesortie=re.sub("\*\*", "*", ligne) #------------------ #Les puces : if re.match("^- ", ligne) : lignesortie= re.sub("^- ", "* ", ligne) if re.match("^\+ ", ligne) : lignesortie= re.sub("^\+ ", "* ", ligne) #Listes numérotées : if dicoRE['ListeNum'].re.match(ligne): counttab=0 for j in range(len(ligne)): if ligne[j]=="\t" : Mantel Page 27 sur 29
Conversion de syntaxes Wiki counttab+=1 lignesortie = re.sub("^(\t)*([0-9#]+\.)*", "#"*(counttab+1), ligne) if re.match(".*_.*", ligne): for clef in dicolinks: print "Ligne : " + ligne print "dico", dicolinks print "match", re.match(str(clef),ligne) matching = clef+"_" print "match", re.match(matching,ligne) print clef+"_" if re.match(clef+"_",ligne): print "SPOTTED !" lignesortie=re.sub(clef+"_", "[["+dicolinks[clef]+"|"+clef+"]]",ligne) if headingspotted == False : if heading2ok == False : fileout.write(lignesortie) else : heading2ok= False ligneante=ligneprec ligneprec=ligne def creationdicolinks(): global dicolinks dicolinks={} for i in range(len(lignesfic)): if re.match("^\.\. .*: ", lignesfic[i]): for j in range(len(lignesfic[i])): if lignesfic[i][j]==":" : pos2points = j break inddico = lignesfic[i][4:pos2points] valdico = lignesfic[i][pos2points+2:len(lignesfic[i])-1] print inddico print valdico dicolinks[inddico]=valdico print dicolinks def creationfichierfinal(format): global fileout fileout=open("sortie"+format,'w') creationdicolinks() for i in range(len(lignesfic)): conversionligneRST2cre(lignesfic[i]) ligneante = "" ligneprec = "" headingok=False heading2ok=False Mantel Page 28 sur 29
Conversion de syntaxes Wiki listedefichiervalides() promptouvrirfichier() formatconvert=promptconversion() creationfichierfinal(formatconvert) Mantel Page 29 sur 29
Vous pouvez aussi lire