« Creatobot » : différence entre les versions

De Wikipast
Aller à la navigation Aller à la recherche
Aucun résumé des modifications
 
(10 versions intermédiaires par 2 utilisateurs non affichées)
Ligne 1 : Ligne 1 :
[[Creatobot]] est un bot codé en language [[Python]], il a pour mission de rechercher des potentiels hypermots afin de rajouter les balises correspondant à des lien [[Wikipast]].
[[Creatobot]] est un bot codé en language [[Python]], il a pour mission de rechercher des potentiels hypermots afin de rajouter les balises correspondant à des liens [[Wikipast]].


== Fonctionnement ==
== Fonctionnement ==
[[Creatobot]] travaille sur les pages créés par les étudiants du cours SHS Humanités Digitals 2018 [http://wikipast.epfl.ch/wikipast/index.php/Biographies]. Il récupère le lien de la page et scanne ensuite le contenu de la page afin d'effectuer une recherche de potentiels hypermots. Pour ce faire il utilise un algorithme bien précis. Le bot omet d’abord les titres, car la [[syntaxe Wikipast]] ne contient pas d'hypermot dans ces derniers,
[[Creatobot]] travaille sur les pages créés par les étudiants du cours SHS Humanités Digitals 2018 [http://wikipast.epfl.ch/wikipast/index.php/Biographies]. Son fonctionnement est le suivant : <br />D’abord il effectue une série d’initialisations : ouverture du dictionnaire, création d’une liste de prénoms francophones à partir de Wikipédia[https://fr.wikipedia.org/wiki/Liste_de_pr%C3%A9noms_fran%C3%A7ais_et_de_la_francophonie], collecte de la liste des pages à modifier (biographies), login sur [[Wikipast]] et finalement chargement du texte de la page à traîter. <br />L’algorithme pour la recherche de potentiels hypermots est le suivant :  Le bot omet d’abord les titres, car la syntaxe [[Wikipast]] ne contient pas d'hypermot dans ces derniers. Il cherche ensuite toutes les occurrences du titre de la page dans le texte et les met entre crochet si elles ne le sont pas déjà. Puis il sépare le texte de la page en un tableau mot avec comme délimitant les espaces et il sépare les mots de la ponctuation qui peut se trouver avant ou après. <br />Le bot est programmé pour ne sélectionner que des groupes de noms composés de deux mots ou plus. Les prénoms ou noms seuls sont donc ignorés, ils génèreraient en effet trop d'erreur de type faux positif. Pour qu'un groupe de noms soit balisé par le bot il faut que tous les mots qui le composent ne contiennent que des lettres, commencent par une majuscule et ne soient pas déjà balisés. Il faut en plus que le premier nom respecte la condition suivante : n’est pas dans le dictionnaire ou est dans la liste des prénoms.
puis il scanne par double mot. Pour réaliser ceci, il sépare le texte de la page en mot, avec comme délimitant les espaces. Pour chaque pair de mot, il commence par enlever la ponctuation si celle-ci existe après le deuxième mot. Il effectue ensuite une batterie de test sur chaque mot. Il test si celui-ci ne contient que des lettres (pas de ponctuation, pas de chiffres, pas de caractères spéciaux) puis ce dernier commence par une majuscule et enfin s'il appartient au dictionnaire francophone. Notons encore que le bot crée sont propre dictionnaire des prénoms francophones, il l'utilise pour tester si un mot, bien que présent dans le dictionnaire appartient à cette liste. Ceci voudrait dire que nous pouvons donc l'inclure. Pour qu'un hypermot soit créé autour d'un double mot il faut donc que les deux mots qui le compose n'appartiennent pas au dictionnaire à moins qu'ils soient dans la liste des prénoms, ne contiennent que des lettres, commencent par une majuscule et ne soit pas déjà entouré d'un hyperlien. Ce bot peut aussi identifier la ponctuation avant un mot tel que l’apostrophe, il est donc capable de créer un hyperlien pour un mot commençant pas un pronom suivi d'une ponctuation, ou un double mot entre guillemet.  


== Généralités ==
== Généralités ==
Ligne 17 : Ligne 16 :
* ''onlyContainLetters'' : Teste si le mot ne contient que des lettres en utilisant les "Regular Expression" [https://docs.python.org/2/library/re.html]
* ''onlyContainLetters'' : Teste si le mot ne contient que des lettres en utilisant les "Regular Expression" [https://docs.python.org/2/library/re.html]
* ''beginWithACapitalLetter'' : Teste si le mot commence avec une majuscule en utilisant aussi les "Regular Expression" [https://docs.python.org/2/library/re.html]
* ''beginWithACapitalLetter'' : Teste si le mot commence avec une majuscule en utilisant aussi les "Regular Expression" [https://docs.python.org/2/library/re.html]
* ''needBrackets'' : Teste si toutes les conditions nécessaires sont remplies
== Limite du Bot ==
== Limite du Bot ==
*Pour l'instant, ce bot ne traite que les doubles mots, il ne peut donc pas détecter les noms composés de plus de deux mots et va même faire des fautes quand cette situation se présente. Effectivement il ne créera un hyperlien que sur les deux premiers mots composant le triple nom.
*[[Creatobot]] ne s'occupe pas des mots uniques nécessitant un hyperlien.
*[[Creatobot]] ne s'occupe pas des mots uniques qui aurait besoin d'un hyperlien, c'est pourtant souvent ces mots qui sont les plus nombreux.


== Code source==
== Code source==
Ligne 28 : Ligne 25 :
###### Creatobot ####
###### Creatobot ####
#################################
#################################


import regex as re
import regex as re
Ligne 40 : Ligne 36 :
summary='Wikipastbot Creatobot'
summary='Wikipastbot Creatobot'


          
 
###################################################################################################
 
### Initialisations :
 
 
#ouverture dictionnnaire
dictionnaryFileName='Lexique382.txt'
dictionnaryFile=open(dictionnaryFileName, encoding='utf-8')
dictionnaryString=dictionnaryFile.read()
dictionnaryLine=dictionnaryString.split('\n')
dictionnary = []
for line in dictionnaryLine:
    dictionnary.append(line.split('\t')[0])
dictionnaryFile.close()
 
#recherche des prénoms francais sur wikipédia
response=urlopen("https://fr.wikipedia.org/wiki/Liste_de_pr%C3%A9noms_fran%C3%A7ais_et_de_la_francophonie")
page_source=response.read()
soupPrenoms=BeautifulSoup(page_source,'html.parser')
prenoms=[]
for dlTag in soupPrenoms.findAll('dl'):
         for ddTag in dlTag.findAll('dd'):
            bTag = ddTag.find('b')
            if bTag:
                aTag = bTag.find('a')
                if aTag:
                    prenoms.append(aTag.string)
 
 
#Accès aux biographies du wikipast
#Accès aux biographies du wikipast
response=urlopen("http://wikipast.epfl.ch/wikipast/index.php/Biographies")
response=urlopen("http://wikipast.epfl.ch/wikipast/index.php/Biographies")
page_source=response.read()
page_source=response.read()
soup=BeautifulSoup(page_source,'html.parser')
soupBiographies=BeautifulSoup(page_source,'html.parser')
biographies=[]
biographies=[]
for primitive in soup.findAll("table"):
for primitive in soupBiographies.findAll("table"):
     for cap_and_count in primitive.findAll("td"):
     for cap_and_count in primitive.findAll("td"):
         for text in cap_and_count.findAll("a"):
         for text in cap_and_count.findAll("a"):
             if text.string != None:
             if text.string != None:
                 biographies.append(text.string)
                 biographies.append(text.string)
   
##for i in range(len(biographies)):
##    print(biographies[i])
##print('\n'+str(len(biographies))+' Biographies dans la liste \n')


# Login request
# Login request
Ligne 76 : Ligne 95 :


#récupération du texte dans la page voulue:
#récupération du texte dans la page voulue:
title = 'Iossif Ermoliev' #il faut remplacer par biographie[i] ici pour tourné sur toutes les pages.
title = 'Test Creatobot' #il faut remplacer par biographie[i] ici pour tourné sur toutes les pages.
result=requests.post(baseurl+'api.php?action=query&titles='+title+'&export&exportnowrap')
result=requests.post(baseurl+'api.php?action=query&titles='+title+'&export&exportnowrap')
soup=BeautifulSoup(result.text, "lxml")
soup=BeautifulSoup(result.text, "lxml")
Ligne 83 : Ligne 102 :




#code principal:
###################################################################################################
def existInDictionnary(word):
 
     if word.lower() in dictionnary and word not in prenoms:
### Fonctions :
        return True
 
     else:
 
        return False
def inDictionnary(word):
   
     return word.lower() in dictionnary
 
def inPrenoms(word):
     return (word.lower()).capitalize() in prenoms


def onlyContainLetters(word):
def onlyContainLetters(word):
     if re.match("^[\w\d_-]*$", word) == None:
     return not re.match("^[\D]*$", word) == None
        return False
 
    else:
        return True
   
def beginWithACapitalLetter(word):
def beginWithACapitalLetter(word):
     if re.match("^[A-Z](.)*$", word) == None:
     return not re.match("^[A-Z](.)*$", word) == None
        return False
 
    else:
#Si le mot ne contient que des lettres et commence par une majuscule
        return True
def needBracketsLight(word):
   
     return onlyContainLetters(word) and beginWithACapitalLetter(word)
def needBrackets(word1,word2):
 
     #si les deux mots pas dans le dico, ne contiennent que des lettres et commencent pas une majuscule
#Si le mot ne contient que des lettres, commence par une majuscule et n'est pas dans le dictionnaire ou est un prénom
     return not existInDictionnary(word1) and not existInDictionnary(word2) and onlyContainLetters(word1) and onlyContainLetters(word2) and beginWithACapitalLetter(word1) and  beginWithACapitalLetter(word2)
def needBracketsHard(word):
     return needBracketsLight(word) and (not inDictionnary(word) or inPrenoms(word))
 
def separatePunctuation(word):
    punctuationAfter = ''
    punctuationBefore = ''
    if re.match('^.+(\p{P}){1,3}$',word): #si on a une ponctuation après un mot
            punctuationAfter = re.search('[\p{P}]{1,3}$',word).group()
            word = re.sub('(\p{P}){1,3}$',"", word)
    if re.match ('^[\w\d_-]{0,1}(\p{P}){1,3}[\w\d_-]+$',word): #si on a une ponctuation avant un mot
            punctuationBefore = re.search('^[\w\d_-]{0,1}[\p{P}]{1,3}',word).group()
            word = re.sub('^[\w\d_-]{0,1}[\p{P}]{1,3}',"", word)
 
    return [word, punctuationBefore, punctuationAfter]
 
def addBracketsAfter(word):
    [word, punctuationBefore, punctuationAfter]=separatePunctuation(word)
    return punctuationBefore+word+']]'+punctuationAfter
 
def addBracketsBefore(word):
    [word, punctuationBefore, punctuationAfter]=separatePunctuation(word)
    return punctuationBefore+'[['+word+punctuationAfter




   
###################################################################################################
#ouverture dictionnnaire     
nom_fichier='C:/Users/nanil/Documents/6.Semester/Digital Humanities/Lexique382/Lexique382.txt'
fichier=open(nom_fichier, encoding='utf-8')
dictionnaryString=fichier.read()
dictionnaryline = dictionnaryString.split('\n')
dictionnary = []
for line in dictionnaryline:
    dictionnary.append(line.split('\t')[0])


#recherche des prénoms francais sur wikipédia
### Algorithme :
response=urlopen("https://fr.wikipedia.org/wiki/Liste_de_pr%C3%A9noms_fran%C3%A7ais_et_de_la_francophonie")
page_source=response.read()
soup=BeautifulSoup(page_source,'html.parser')
prenoms=[]
for dlTag in soup.findAll('dl'):
        for ddTag in dlTag.findAll('dd'):
            bTag = ddTag.find('b')
            if bTag:
                aTag = bTag.find('a')
                if aTag:
                    prenoms.append(aTag.string)


#Prend les groupes de noms composés de 2 noms ou plus.
#Il faut que le premier nom ne contienne que des lettres et commence par une majuscule et qu'il soit : soit pas dans le dictionnaire, soit dans la liste des prénoms.
#Pour les noms suivants ils doivent simplement ne contenir que des lettres et commencer par une majuscule.




#début algorithme
newText = ''
newText = ''
for line in lines:
 
     words = line.split(" ")
#Découpage du texte en ligne
     if not re.match('^[=]{1,6}[\s]*' + soup.title.text + '[\s]*[=]{1,6}$', line):
j=0
         i = 0
while j < len(lines) :
         while i< len(words)-1:
     line=lines[j]
             #on cherche ceux qui ont déjà une balise pour les exclure
     if not re.match('^[=]{1,6}.*[=]{1,6}$', line): #Si la ligne n'est pas un titre
             if re.match('[\[]{2}(.)*', words[i]): #début séquence avec [[
        #Mise en forme des référence au titre de la page
                 while not re.match('(.)*[\]]{2}', words[i]) and i<len(words)-1: #fin séquence ]]
        line=line.replace('[['+soup.title.text+']]',soup.title.text)
                     i += 1
        line=line.replace(soup.title.text,'[['+soup.title.text+']]')
                i += 1
 
            #on cherche ceux qui n'en ont pas et ou l'on veut en mettre (double mot pour l'instant)
        words = line.split(" ") #Découpage du texte en mot
            else:
 
                #rechercher de nom en deux mots:
        modifyFlag = False #Flag pour la gestion groupe de noms
                doubleWord = words[i] + ' ' + words[i+1]
        firstWord = False
                punctuationAfter = ''
 
                punctuationBefore = ''
         i=0
                if re.match('^[\w\d_-]+(\p{P}){1,3}$',words[i+1]): #si on a une ponctuation après un mot
         while i < len(words):
                         punctuationAfter = re.search('[\p{P}]{1,3}$',words[i+1]).group()
 
                        words[i+1] = re.sub('(\p{P}){1,3}$',"", words[i+1])
             #Evitement des mots déjà balisés
                if re.match ('^[\w\d_-]{0,1}(\p{P}){1}[\w\d_-]+$',words[i]): #si on a une ponctuation avant un mot
             if re.match('[\[]{2}(.)*', words[i]): #Si présence d'une balise
                         punctuationBefore = re.search('^[\w\d_-]{0,1}[\p{P}]{1}',words[i]).group()
                flag = True #Flag pour la gestion des mot déjà balisé
                         words[i] = re.sub('^[\w\d_-]{0,1}[\p{P}]{1}',"", words[i])
                wordID = i;
                if doubleWord == soup.title.text or needBrackets(words[i],words[i+1]): #si c'est le titre ou si le test ok
                 while i < len(words)-1 and flag :
                     words[i] = '[[' + words[i]
                    [wordNoPunc, punctuationBefore, punctuationAfter]=separatePunctuation(words[i])
                     words[i] = punctuationBefore + words[i]
 
                     words[i+1] = words[i+1] + ']]'
                     if i == wordID :
                     words[i+1] = words[i+1] + punctuationAfter
                        if punctuationBefore != '[[' :
                i+=1
                            words[wordID]=re.sub('^[\[]{2}',"", words[wordID])
    line = ' '.join(words)
                            flag = False
                            i=-1
                        elif punctuationAfter == ']]' :
                            flag = False
                         elif punctuationAfter != '' :
                            words[wordID]=re.sub('^[\[]{2}',"", words[wordID])
                            flag = False
                            i=-1
                    else :
                        if punctuationBefore != '' :
                            words[wordID]=re.sub('^[\[]{2}',"", words[wordID])
                            flag = False
                            i=-1
                         elif punctuationAfter == ']]' :
                            flag = False
                         elif punctuationAfter != '' :
                            words[wordID]=re.sub('^[\[]{2}',"", words[wordID])
                            flag = False
                            i=-1
                    i+=1
 
            else :
                [wordNoPunc, punctuationBefore, punctuationAfter]=separatePunctuation(words[i])
 
                if modifyFlag :
                     if firstWord :
                        firstWord=False
                        if needBracketsLight(wordNoPunc) :
                            words[i-1]=addBracketsBefore(words[i-1])
                        else :
                            modifyFlag=False
                     else :
                        if not needBracketsLight(wordNoPunc) :
                            words[i-1]=addBracketsAfter(words[i-1])
                            modifyFlag=False
 
                #Ouverture des balises si elles ne sont pas déjà ouvertes et si le test est ok
                elif needBracketsHard(wordNoPunc):
                    modifyFlag = True
                     firstWord = True
 
                #Fermeture des balises si dernier mot ou si ponctuation après le mot
                if modifyFlag and needBracketsLight(wordNoPunc) and (i == len(words)-1 or punctuationAfter != '') :
                     modifyFlag=False
                    if not firstWord :
                        words[i]=addBracketsAfter(words[i])
 
            i+=1
        line = ' '.join(words)
     newText += line + '\n'
     newText += line + '\n'
    j+=1
print(newText)
print(newText)




###################################################################################################


### Ecriture de la page :


##décommenter pour que le bot change la page wiki:


payload={'action':'edit','assert':'user','format':'json','utf8':'','text':newText,'summary':summary,'title':title,'token':edit_token}
payload={'action':'edit','assert':'user','format':'json','utf8':'','text':newText,'summary':summary,'title':title,'token':edit_token}

Dernière version du 15 mai 2018 à 12:57

Creatobot est un bot codé en language Python, il a pour mission de rechercher des potentiels hypermots afin de rajouter les balises correspondant à des liens Wikipast.

Fonctionnement

Creatobot travaille sur les pages créés par les étudiants du cours SHS Humanités Digitals 2018 [1]. Son fonctionnement est le suivant :
D’abord il effectue une série d’initialisations : ouverture du dictionnaire, création d’une liste de prénoms francophones à partir de Wikipédia[2], collecte de la liste des pages à modifier (biographies), login sur Wikipast et finalement chargement du texte de la page à traîter.
L’algorithme pour la recherche de potentiels hypermots est le suivant : Le bot omet d’abord les titres, car la syntaxe Wikipast ne contient pas d'hypermot dans ces derniers. Il cherche ensuite toutes les occurrences du titre de la page dans le texte et les met entre crochet si elles ne le sont pas déjà. Puis il sépare le texte de la page en un tableau mot avec comme délimitant les espaces et il sépare les mots de la ponctuation qui peut se trouver avant ou après.
Le bot est programmé pour ne sélectionner que des groupes de noms composés de deux mots ou plus. Les prénoms ou noms seuls sont donc ignorés, ils génèreraient en effet trop d'erreur de type faux positif. Pour qu'un groupe de noms soit balisé par le bot il faut que tous les mots qui le composent ne contiennent que des lettres, commencent par une majuscule et ne soient pas déjà balisés. Il faut en plus que le premier nom respecte la condition suivante : n’est pas dans le dictionnaire ou est dans la liste des prénoms.

Généralités

  • Concepteurs : Amandine Evard, Natalija Ljubic, Duruz Noé, Bourquin Vladimir
  • UserName : Creatobot

Exemple de pages modifiées

Liste des fonctions

  • existInDictionnary : Teste si le mot existe dans le dictionnaire[4] et si il existe dans la liste des prénoms francophones [5]
  • onlyContainLetters : Teste si le mot ne contient que des lettres en utilisant les "Regular Expression" [6]
  • beginWithACapitalLetter : Teste si le mot commence avec une majuscule en utilisant aussi les "Regular Expression" [7]

Limite du Bot

  • Creatobot ne s'occupe pas des mots uniques nécessitant un hyperlien.

Code source


#################################
###### Creatobot ####
#################################

import regex as re
import requests
from urllib.request import urlopen
from bs4 import BeautifulSoup

user='Creatobot'
passw='creatobot_mdp'
baseurl='http://wikipast.epfl.ch/wikipast/'
summary='Wikipastbot Creatobot'


###################################################################################################

### Initialisations :


#ouverture dictionnnaire
dictionnaryFileName='Lexique382.txt'
dictionnaryFile=open(dictionnaryFileName, encoding='utf-8')
dictionnaryString=dictionnaryFile.read()
dictionnaryLine=dictionnaryString.split('\n')
dictionnary = []
for line in dictionnaryLine:
    dictionnary.append(line.split('\t')[0])
dictionnaryFile.close()

#recherche des prénoms francais sur wikipédia
response=urlopen("https://fr.wikipedia.org/wiki/Liste_de_pr%C3%A9noms_fran%C3%A7ais_et_de_la_francophonie")
page_source=response.read()
soupPrenoms=BeautifulSoup(page_source,'html.parser')
prenoms=[]
for dlTag in soupPrenoms.findAll('dl'):
        for ddTag in dlTag.findAll('dd'):
            bTag = ddTag.find('b')
            if bTag:
                aTag = bTag.find('a')
                if aTag:
                    prenoms.append(aTag.string)


#Accès aux biographies du wikipast
response=urlopen("http://wikipast.epfl.ch/wikipast/index.php/Biographies")
page_source=response.read()
soupBiographies=BeautifulSoup(page_source,'html.parser')
biographies=[]
for primitive in soupBiographies.findAll("table"):
    for cap_and_count in primitive.findAll("td"):
        for text in cap_and_count.findAll("a"):
            if text.string != None:
                biographies.append(text.string)

# Login request
payload={'action':'query','format':'json','utf8':'','meta':'tokens','type':'login'}
r1=requests.post(baseurl + 'api.php', data=payload)

#login confirm
login_token=r1.json()['query']['tokens']['logintoken']
payload={'action':'login','format':'json','utf8':'','lgname':user,'lgpassword':passw,'lgtoken':login_token}
r2=requests.post(baseurl + 'api.php', data=payload, cookies=r1.cookies)

#get edit token2
params3='?format=json&action=query&meta=tokens&continue='
r3=requests.get(baseurl + 'api.php' + params3, cookies=r2.cookies)
edit_token=r3.json()['query']['tokens']['csrftoken']

edit_cookie=r2.cookies.copy()
edit_cookie.update(r3.cookies)

#récupération du texte dans la page voulue:
title = 'Test Creatobot' #il faut remplacer par biographie[i] ici pour tourné sur toutes les pages.
result=requests.post(baseurl+'api.php?action=query&titles='+title+'&export&exportnowrap')
soup=BeautifulSoup(result.text, "lxml")
#prend la partie de la page qui est le texte
lines = soup.find('page').find('text').text.split('\n')


###################################################################################################

### Fonctions :


def inDictionnary(word):
    return word.lower() in dictionnary

def inPrenoms(word):
    return (word.lower()).capitalize() in prenoms

def onlyContainLetters(word):
    return not re.match("^[\D]*$", word) == None

def beginWithACapitalLetter(word):
    return not re.match("^[A-Z](.)*$", word) == None

#Si le mot ne contient que des lettres et commence par une majuscule
def needBracketsLight(word):
    return onlyContainLetters(word) and beginWithACapitalLetter(word)

#Si le mot ne contient que des lettres, commence par une majuscule et n'est pas dans le dictionnaire ou est un prénom
def needBracketsHard(word):
    return needBracketsLight(word) and (not inDictionnary(word) or inPrenoms(word))

def separatePunctuation(word):
    punctuationAfter = ''
    punctuationBefore = ''
    if re.match('^.+(\p{P}){1,3}$',word): #si on a une ponctuation après un mot
            punctuationAfter = re.search('[\p{P}]{1,3}$',word).group()
            word = re.sub('(\p{P}){1,3}$',"", word)
    if re.match ('^[\w\d_-]{0,1}(\p{P}){1,3}[\w\d_-]+$',word): #si on a une ponctuation avant un mot
            punctuationBefore = re.search('^[\w\d_-]{0,1}[\p{P}]{1,3}',word).group()
            word = re.sub('^[\w\d_-]{0,1}[\p{P}]{1,3}',"", word)

    return [word, punctuationBefore, punctuationAfter]

def addBracketsAfter(word):
    [word, punctuationBefore, punctuationAfter]=separatePunctuation(word)
    return punctuationBefore+word+']]'+punctuationAfter

def addBracketsBefore(word):
    [word, punctuationBefore, punctuationAfter]=separatePunctuation(word)
    return punctuationBefore+'[['+word+punctuationAfter


###################################################################################################

### Algorithme :

#Prend les groupes de noms composés de 2 noms ou plus.
#Il faut que le premier nom ne contienne que des lettres et commence par une majuscule et qu'il soit : soit pas dans le dictionnaire, soit dans la liste des prénoms.
#Pour les noms suivants ils doivent simplement ne contenir que des lettres et commencer par une majuscule.


newText = ''

#Découpage du texte en ligne
j=0
while j < len(lines) :
    line=lines[j]
    if not re.match('^[=]{1,6}.*[=]{1,6}$', line): #Si la ligne n'est pas un titre
        #Mise en forme des référence au titre de la page
        line=line.replace('[['+soup.title.text+']]',soup.title.text)
        line=line.replace(soup.title.text,'[['+soup.title.text+']]')

        words = line.split(" ") #Découpage du texte en mot

        modifyFlag = False #Flag pour la gestion groupe de noms
        firstWord = False

        i=0
        while i < len(words):

            #Evitement des mots déjà balisés
            if re.match('[\[]{2}(.)*', words[i]): #Si présence d'une balise
                flag = True #Flag pour la gestion des mot déjà balisé
                wordID = i;
                while i < len(words)-1 and flag :
                    [wordNoPunc, punctuationBefore, punctuationAfter]=separatePunctuation(words[i])

                    if i == wordID :
                        if punctuationBefore != '[[' :
                            words[wordID]=re.sub('^[\[]{2}',"", words[wordID])
                            flag = False
                            i=-1
                        elif punctuationAfter == ']]' :
                            flag = False
                        elif punctuationAfter != '' :
                            words[wordID]=re.sub('^[\[]{2}',"", words[wordID])
                            flag = False
                            i=-1
                    else :
                        if punctuationBefore != '' :
                            words[wordID]=re.sub('^[\[]{2}',"", words[wordID])
                            flag = False
                            i=-1
                        elif punctuationAfter == ']]' :
                            flag = False
                        elif punctuationAfter != '' :
                            words[wordID]=re.sub('^[\[]{2}',"", words[wordID])
                            flag = False
                            i=-1
                    i+=1

            else :
                [wordNoPunc, punctuationBefore, punctuationAfter]=separatePunctuation(words[i])

                if modifyFlag :
                    if firstWord :
                        firstWord=False
                        if needBracketsLight(wordNoPunc) :
                            words[i-1]=addBracketsBefore(words[i-1])
                        else :
                            modifyFlag=False
                    else :
                        if not needBracketsLight(wordNoPunc) :
                            words[i-1]=addBracketsAfter(words[i-1])
                            modifyFlag=False

                #Ouverture des balises si elles ne sont pas déjà ouvertes et si le test est ok
                elif needBracketsHard(wordNoPunc):
                    modifyFlag = True
                    firstWord = True

                #Fermeture des balises si dernier mot ou si ponctuation après le mot
                if modifyFlag and needBracketsLight(wordNoPunc) and (i == len(words)-1 or punctuationAfter != '') :
                    modifyFlag=False
                    if not firstWord :
                        words[i]=addBracketsAfter(words[i])

            i+=1
        line = ' '.join(words)
    newText += line + '\n'
    j+=1

print(newText)


###################################################################################################

### Ecriture de la page :


payload={'action':'edit','assert':'user','format':'json','utf8':'','text':newText,'summary':summary,'title':title,'token':edit_token}
r4=requests.post(baseurl+'api.php',data=payload,cookies=edit_cookie)
print(r4.text)