#MODE D'EMPLOI SUR LE TERMINAL : python3 bao3_extract_patron_v2.py fichier-tt.xml PATRON1 -- PATRON2 -- PATRONn -- ... #La classe List dans le module typing permet d'indiquer le type de variable qu'on attend from typing import List import re, sys #-------------------------------------------------------------- #On définit une fonction extract() qui va prendre en entrée un corpus (string) et une liste de strings qui correspondra au patron. def extract(corpus_file:str, patron:List[str]): #On crée un buffer. Le buffer prendra la forme d'une liste de tuple (POS-forme), avec autant de tuples qu'il y a d'éléments dans le patron. #On met dans le buffer des strings qu'on sait ne vont pas matcher notre regex. On est obligé de faire ça car sinon, il risque d'y avoir une erreur lorsque l'on va utiliser "pop" sur un buffer vide. buf=[("---", "---")] * len(patron) #On ouvre notre corpus. with open(corpus_file) as corpus : #On va parcourir le corpus ligne par ligne. for line in corpus: #"pop(0)" enlève le premier élément de la liste #On enlève avec "pop(0)" le premier élément de notre buffer, c'est-à-dire le premier tuple. buf.pop(0) #On cherche dans la ligne tout ce qui se trouve dans la balise qui correspond à la POS du token et dans qui correspond à sa forme. match=re.match("([^<]+?)<\/data>[^<]+?<\/data>([^<]+?)<\/data><\/element>", line) #Si ça match : if match: #On met ce qui se trouve dans le groupe de capture 1 (la POS) dans la variable "tag". tag=match.group(1) #On met ce qui se trouve dans le groupe de capture 2 (la forme) dans la variable "forme". forme=match.group(2) #On rajoute ce tuple de tag-forme à notre buffer. buf.append((tag, forme)) #Si ça ne match pas, c'est soit qu'on est dans les lignes d'entête ou de fin de fichier, soit qu'on change de phrase. Donc on réinitialise le buffer pour ne pas avoir de patrons qui commence dans une phrase et se termine dans une autre. else: buf=[("---", "---")] * len(patron) #On initialise un booléen qui va nous permettre de checker que ce qui est contenu dans le buffer correspond à notre patron. ok=True #On initialise une string vide dans laquelle on mettra la forme du token si sa POS correspond à notre patron. terme="" #Pour chaque élément du patron: for i, gat in enumerate(patron): #Si l'élément i du patron correspond entièrement au début du premier élément du tuple i (c'est-à-dire la POS) du buffer : #On doit faire ça pour pouvoir match un "DET:ART" avec juste un DET dans notre patron. if re.match(gat, buf[i][0]): #On ajoute le deuxième élément du tuple i (la forme) à la string "terme" suivi d'un espace. terme=terme+buf[i][1]+" " #Si l'élément i du patron ne correspond pas au premier élément du tuple i, le booléen devient "False" et on sort de la boucle. else: ok=False break #Si le booléen est "True", cela signifie que le buffer correspond bien au patron. On ajoute notre terme à notre fichier. if ok: f.write(terme+"\n") #-------------------------------------------------------------- #On définit la fonction segmentation_patrons. Cette fonction prend en entrée une liste et renvoie une liste de listes pour pouvoir séparer chaque patron dans des listes distinctes. def segmentation_patrons(liste): #On crée une liste vide dans laquelle on mettra les listes de patrons. liste_patrons=[] #On crée une liste tampon tmp=[] #Pour tous les items qui se trouvent dans notre liste en entrée : for i in range(len(liste)): #Si l'item est "--", ça veut dire qu'un nouveau patron commence. if liste[i]=="--": #Donc on rajoute notre liste tampon à la liste de patrons et on vide la liste tampon pour le prochain patron. liste_patrons.append(tmp) tmp=[] #Autrement, ça veut dire qu'on est toujours dans le même patron, donc on rajoute seulement l'élément à notre liste tampon. else: tmp.append(liste[i]) #On rajoute cette ligne là pour ajouter le dernier patron à la liste. Si on ne met pas cette ligne, comme on ne rencontrera plus jamais de "--", le dernier patron ne sera jamais rajouté. liste_patrons.append(tmp) #On renvoie la liste de patrons. return liste_patrons #-------------------------------------------------------------- #On définit la fonction qui va permettre de créer la liste utilisée pour le nommage des fichiers. Elle prend en entrée une liste de listes de patrons et renvoyer une liste dont chaque élément est un nom de patron formaté au format XX-XX-XX. def pretty_names(liste): #On crée une liste vide dans laquelle on va mettre les noms des patrons. noms_patrons=[] #On crée une string tampon vide. tmp="" #Pour chaque patron de notre liste de patrons : for patron in liste: #Pour chaque élément du patron: for i in range(len(patron)): #Si patron[i] correspond au dernier élément du patron, on l'ajoute tout simplement à la string tampon. Sinon, le fichier se finirait par "-.txt" et ce n'est pas très joli. if i==len(patron)-1: tmp+=patron[i] #Sinon, on rajoute l'élémént à la string tampon suivi d'un tiret. Pour que chaque POS soit séparée d'un tiret. else: tmp+=patron[i]+"-" #On ajoute notre string tampon à la liste des noms des patrons et on vide la string tampon. noms_patrons.append(tmp) tmp="" #On renvoie la liste des noms. return noms_patrons #-------------------------------------------------------------- if __name__=="__main__": #Le premier argument de la liste d'argument est mis dans la variable "corpus_file". corpus_file=sys.argv[1] #On récupère le numéro de la rubrique pour le nommage des fichiers de sortie. m=re.search("(\d+).xml", corpus_file) rubrique=m.group(1) #A partir du deuxième argument jusqu'à la fin, on a le ou les patrons qu'on met dans la liste "patrons". patrons=sys.argv[2:] #On fait passer notre liste par la fonction segmentation_patrons() pour pouvoir avoir une liste de listes avec un patron par sous-liste. liste_patrons=segmentation_patrons(patrons) #On fait passer notre liste de patrons par pretty_names() pour pouvoir nommer les fichier de sortie de façon jolie. noms_patrons=pretty_names(liste_patrons) #Pour chaque patron de notre liste de patrons : for i in range(len(liste_patrons)): #On fait afficher sur le terminal le patron que l'on est en train de traiter print(f"On traite le patron {noms_patrons[i]}...") #On ouvre le fichier dans lequel sera écrit les résultats. Dans son nom, on met le numéro de la rubrique ainsi que le patron et "tt" car on prend en entrée un fichier TreeTagger. f=open(f"extract_patron_{rubrique}_tt_lecture_buffer_{noms_patrons[i]}.txt", "w", encoding="utf-8") #On lance la fonction extract avec notre corpus et le patron morphosyntaxique. extract(corpus_file, liste_patrons[i]) #On ferme le fichier de résultats. f.close()