# -*- coding: iso-8859-1 -*- # Copyright 20003 - 2008: Julien Bourdaillet (julien.bourdaillet@lip6.fr), Jean-Gabriel Ganascia (jean-gabriel.ganascia@lip6.fr) # This file is part of MEDITE. # # MEDITE is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # MEDITE is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Foobar; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import os,os.path,sys,string,logging,htmlentitydefs,bisect import contract import constantes import Donnees.resultatAppli import Controleurs.DGManager import Utile.constantesDonnees from string import Template import utile #import scipy import numpy.oldnumeric as Numeric class ListManager(object): """ Classe centralisant la gestion d'une liste de valeurs fixes """ def __init__(self): self._liste = [] def getListe(self): """ Liste des tags """ return self._liste def getItem(self,pos): return self._liste[pos] def getNbItems(self): """ Nombre de tags """ return len(self._liste) def itemToPos(self,item): """ Renvoie la position du tag dans la liste des tags """ #return self._liste.index(item) try: return self._liste.index(item) except ValueError: raise ValueError("list.index(x): x not in list, x="+str(item)) def posToItem(self,pos): """ Renvoie le tag correspondant à cette position dans la liste de tags """ if not(0<=pos<=len(self._liste)): raise LookupError("index out of range") else: return self._liste[pos] def pref(self,item,num): """ renvoie le préfixe de item pre: isinstance(item,str) or isinstance(item,list) """ if isinstance(item,str): return self.__pref(item,num) res = [] for x in item: res.append(self.__pref(x,num)) return res def __pref(self,item,num): res = item[:num] #sepTable = string.maketrans("çéèàùâêîôûäëïöüÿÇÉÈÀÙÂÊÎÔÛÄËÏÖÜ","ceeauaeiouaeiouyCEEAUAEIOUAEIOU") #res = res.translate(sepTable) if item[-1]=='1' or item[-1]=='2': res += ' T'+item[-1] return res class TagManager(ListManager): """ Classe centralisant la gestion de la liste de tags utilisés """ def __init__(self): self._liste = ['ABR', 'ADJ', 'ADV', 'DET', 'INT', 'KON', 'NAM', 'NOM', 'NUM', 'PRO', 'PRP', 'PUN', 'SENT', 'SYM', 'VER'] def getDescriptions(self): return [u'Abréviation', 'Adjectif', 'Adverbe', u'Déterminant', 'Interjection', 'Conjonction', 'Nom propre', 'Nom', u'Numéral', 'Pronom', u'Préposition', 'Ponctuation', 'Mot phrase', 'Symbole', 'Verbe'] class TagManager2(TagManager): """ Classe centralisant la gestion de la liste de tags utilisés """ def __init__(self): #self._liste = ['Supp + Remp1', 'Ins + Remp2', 'BC1', 'BC2'] self._liste = ['Modifications', 'BC'] def getDescriptions(self): #return ['Suppressions + Remplacements 1', 'Insertions + Remplacements 2', # 'Blocs Communs', 'Blocs Communs'] return ['Modifications', 'Blocs Communs'] class PartOfTextManager(ListManager): """ Classe centralisant la gestion des différentes parties du texte """ def __init__(self): self._liste = ['Suppressions', 'Insertions', 'Remplacements1', 'Remplacements2', u'Déplacements1', u'Déplacements2', 'Blocs Communs 1', 'Blocs Communs 2', 'Texte1', 'Texte2'] def abreviations(self,num=None): """ Renvoie une abréviation ou toute la liste pre: num==None or num<=len(self._liste) """ res = self.pref(self._liste[:2],3) + self.pref(self._liste[2:4],4) + self.pref(self._liste[4:],3) if num==None: return res else: return res[num] class PartOfTextManager2(PartOfTextManager): """ (Sup,Remp1) et (Ins,Remp2) sont fusionnés """ def __init__(self): self._liste = ['Suppressions + Remp1', 'Insertions + Remp2', u'Déplacements1', u'Déplacements2', 'Blocs Communs 1', 'Blocs Communs 2', 'Texte1', 'Texte2'] class PartOfTextManager3(PartOfTextManager): """ Affiche les BC et les Dep """ def __init__(self): self._liste = ['Blocs Communs 1','Blocs Communs 2', u'Déplacements1', u'Déplacements2', u'BC1 + Dép1', u'BC2 + Dép2', 'Texte1', 'Texte2'] class PartOfTextManager4(PartOfTextManager): """ (Sup+Remp1)/BC1 et (Ins+Remp2)/BC2 """ def __init__(self): self._liste = ['Texte1', 'Texte2'] class TreeTaggerWrapper(object): """Classe qui interface le TreeTagger. A partir d'un texte, renovie une liste des tokens étiquetés, en appellant la fonction etiquetage()""" def __init__(self): self._REPTAGGER = os.path.join(constantes.REPMEDITE,"TreeTagger") if not os.path.isdir(self._REPTAGGER): raise IOError,"Le dossier TreeTagger est absent." #self._TAGGER = os.path.join(self._REPTAGGER,"tag-french.bat") self._TAGGER = "tag-french.bat" # nom du tagger #if not os.path.isfile(self._TAGGER): raise IOError,"Le TreeTagger est absent." def exec_pipe(self,directory,cmd,arg): """ Exécute la commande cmd en lui passant sur stdin arg et en récupérant le résultat sur stdout pre: isinstance(directory,str) isinstance(cmd,str) isinstance(arg,str) os.path.isfile(cmd) post: isinstance(__return__,str) """ curDir=os.getcwd() os.chdir(directory) #print "directory",directory #print "cmd",cmd fi,fo,fe = os.popen3(cmd,'t') assert(fi != None) assert(fo != None) #fi.writelines(arg) fi.close() resultat = fo.readlines() err = fe.readlines() fo.close() fe.close() if 'ERROR' in err: sys.stderr.write(str(err)) if len(resultat)==0: raise ValueError,u"Résultat de la commande vide." resultat = ''.join(resultat) os.chdir(curDir) return resultat def etiquetage(self,texte): """ Lance l'étiqueteur sur le texte et renvoie une liste [(token,tag)] post: isinstance(__return__,list) """ nom_fichier_temp = "medTemp.txt" fichier_temp = os.path.join(self._REPTAGGER,"medTemp.txt") ft = open(fichier_temp, 'w') ft.write(texte) ft.close() #if not os.path.isfile(fichier_temp): raise IOError,u"Fichier temporaire non créé." #textTagged = self.exec_pipe(self._REPTAGGER,self._TAGGER +' "'+ fichier_temp+'"', "") #textTagged = self.exec_pipe(self._REPTAGGER,self._TAGGER, fichier_temp) # le tagger et le fichier à tagger doivent se trouver dans le même dossier textTagged = self.exec_pipe(self._REPTAGGER,self._TAGGER + ' ' +nom_fichier_temp,'') os.remove(fichier_temp) lLines = textTagged.splitlines() if len(lLines)==0: raise ValueError,u"L'étiquetage a échoué." lTokenTag = [] for l in lLines: lTok = l.split() if len(lTok)<=1: continue # le token dans lTok[0] et le tag dans lTok[1] auquel on enlève le soustag #print "1",lTok,"2" end = lTok[1].find(':') if end==-1: end=len(lTok[1]) lTokenTag.append((lTok[0],lTok[1][:end])) return lTokenTag class TaggerExtension(object): """Classe gérant l'étiquetage des textes """ def __init__(self,res): """ Constructeur pre: isinstance(res,Donnees.resultatAppli.Resultat) """ self.resultatMedite = res self.tm = TagManager() def etiquetage(self): """ Lance l'étiqueteur sur le texte et renvoie une liste [(token,tag)] On traite les 2 fichiers séparément car si le 1er ne se termine pas par un séparateur, son denier mot est concaténé au 1er du 2e fichier. post: isinstance(__return__,list) """ tagger = TreeTaggerWrapper() texte = self.resultatMedite.getTextesConcatenes() lgSource=self.resultatMedite.getLgSource() lTokenTag = [] lTokenTag = tagger.etiquetage(texte[:lgSource]) self._printTaggerOutput(lTokenTag, 'TreeTaggerOutputGauche.txt') #print 'lTokenTag='+str(lTokenTag) a = tagger.etiquetage(texte[lgSource:]) self._printTaggerOutput(a, 'TreeTaggerOutputDroite.txt') #print 'a='+str(a) lTokenTag.extend(a) return lTokenTag def _printTaggerOutput(self, liste, nom): fichier = open(os.path.join(constantes.REPMEDITE,nom),'w') for token,tag in liste: fichier.write(token + '\t' + tag + '\n') fichier.close() def extractLTokenPos_(self): """ Extrait à partir du texte original une liste [(token, position)] Traite le texte source puis le texte cible post: isinstance(__return__,list) """ texte = self.resultatMedite.getTextesConcatenes() lgSource = self.resultatMedite.getLgSource() lTokenPos = [] lTokenPos = self.extractLTokenPos__(texte[:lgSource],0) #print lTokenPos b = self.extractLTokenPos__(texte[lgSource:],lgSource) lTokenPos.extend(b) #print 'b='+str(b) return lTokenPos def extractLTokenPos__(self,texte,debutTexte): """ Extrait à partir du texte original une liste [(token, position)] pre: isinstance(texte,str) and isinstance(debutTexte,int) and debutTexte>=0 post: isinstance(__return__,list) """ lTokenPos = [] currentToken = [] debutToken = i = 0 while i < len(texte): #print 'texte[i]='+texte[i] assert len(currentToken) <= len(texte),(len(currentToken), len(texte)) # pas + de token que de caractères assert len(lTokenPos) <= len(texte),(len(lTokenPos), len(texte)) # pas de token > au texte if (texte[i] in """ .-'[]{}`"(),;:!?%»«\t\r\n\f"""):# or (i==lgSource): if len(currentToken) > 0: lTokenPos.append((''.join(currentToken), debutToken+debutTexte)) #print ''.join(currentToken) +' added' #print lTokenPos[-1] currentToken = [] debutToken = i # les mêmes sauf espace et retour ligne cad ceux qui ne sont pas des # signes de ponctuation if i < len(texte) and texte[i] in """.-'[]{}`"(),;:!?%»«""": lTokenPos.append((texte[i], debutToken+debutTexte)) #print texte[i] + ' added' i += 1 else: while i < len(texte) and (texte[i] in " \t\r\n\f"): i+=1 debutToken = i #if i==lgSource: i+=1 else: currentToken.append(texte[i]) i+=1 if currentToken != []: lTokenPos.append((''.join(currentToken), debutToken+debutTexte)) #print ''.join(currentToken) return lTokenPos def alignement(self): """ Aligne la liste (token,tag) et la liste (token,position) en une liste [(debutToken,finToken,tag)] post: isinstance(__return__,list) """ lTokenTag = self.etiquetage() lTokenPos = self.extractLTokenPos_() return self.alignement_(lTokenPos, lTokenTag) def alignement_(self, lTokenPos, lTokenTag): """ Aligne les 2 listes en créant une liste [(debutToken,finToken,tag)] pre: isinstance(lTokenTag, list) isinstance(lTokenPos, list) post: isinstance(__return__,list) """ res = [] maxi = maxj = 0 while lTokenPos <> [] or lTokenTag <> []: #print (len(lTokenTag), len(lTokenPos)) if lTokenPos == []: raise ValueError, "lTokenPos can't be []" elif lTokenTag == []: raise ValueError, "lTokenTag can't be []" elif lTokenPos[0][0] == lTokenTag[0][0]: res.append((lTokenPos[0][1],lTokenPos[0][1]+len(lTokenPos[0][0]),lTokenTag[0][1])) lTokenPos = lTokenPos[1:] lTokenTag = lTokenTag[1:] else: i = j = 0 startPos = endPos = lTokenPos[j][1] conclTag = lTokenTag[i][0] conclPos = lTokenPos[j][0] while conclTag != conclPos: if len(conclTag) < len(conclPos): i += 1 conclTag += lTokenTag[i][0] endPos += len(lTokenTag[i][0]) if i > maxi: maxi = i else: j += 1 conclPos += lTokenPos[j][0] endPos += len(lTokenPos[j][0]) if j > maxj: maxj = j #print conclTag #print conclPos res.append((startPos,endPos,lTokenTag[i][1])) #sys.stdout.write("align: "+str(conclTag)+" / "+str(conclPos)+" / "+str(lTokenTag[0])+" lTokenTag[i][1]) "+str(lTokenTag[i][1])+ " / i="+str(i)+" / j=+"+str(j)+"\n") lTokenTag = lTokenTag[i+1:] lTokenPos = lTokenPos[j+1:] if i > maxi: maxi = i if j > maxj: maxj = j #print res[-1] sys.stdout.write("len(s1) "+str(len(lTokenPos))+" / len(s2)"+str(len(lTokenTag))+" / maxi="+str(maxi)+"\n") return res def post_traitement_alignement(self,liste): """ Conversion de la liste [(debut,fin,tag)] en dictionnaire pre: isinstance(liste,list) post: isinstance(__return__,dict) """ dic = {} for (debut,fin,tag) in liste: dic[debut] = (fin,tag) return dic def calcul_frequences(self,la,da): """ Crée la matrice de fréquences pre: isinstance(la,list) isinstance(da,dict) post: isinstance(__return__,TagFrequencyMatrix) """ a = self.__sum_tag(self.resultatMedite.getListeDeplacementsT1(),da), b = self.__sum_tag(self.resultatMedite.getListeDeplacementsT2(),da) L1=[] ; L2=[] for d,f in self.resultatMedite.getListeDeplacementsT1(): L1.append(self.resultatMedite.getTextesConcatenes()[d:f]) for d,f in self.resultatMedite.getListeDeplacementsT2(): L2.append(self.resultatMedite.getTextesConcatenes()[d:f]) for d,f in self.resultatMedite.getListeDeplacementsT2(): c=self.resultatMedite.getTextesConcatenes()[d:f] if c in L1: L1.remove(c) for d,f in self.resultatMedite.getListeDeplacementsT1(): d=self.resultatMedite.getTextesConcatenes()[d:f] if d in L2: L2.remove(d) logging.debug('L1='+str(L1)) logging.debug('L2='+str(L2)) L3=[] ; L4=[] for d,f in self.resultatMedite.getBlocsCommunsT1(): L3.append(self.resultatMedite.getTextesConcatenes()[d:f]) for d,f in self.resultatMedite.getBlocsCommunsT2(): L4.append(self.resultatMedite.getTextesConcatenes()[d:f]) for d,f in self.resultatMedite.getBlocsCommunsT2(): c=self.resultatMedite.getTextesConcatenes()[d:f] if c in L3: L3.remove(c) for d,f in self.resultatMedite.getBlocsCommunsT1(): d=self.resultatMedite.getTextesConcatenes()[d:f] if d in L4: L4.remove(d) logging.debug('L3='+str(L3)) logging.debug('L4='+str(L4)) assert len(L3) == len(L4) == 0, (len(L3), len(L4)) freqGeneticModifs = Numeric.array( [self.__sum_tag(self.resultatMedite.getListeSuppressions(),da), self.__sum_tag(self.resultatMedite.getListeInsertions(),da), self.__sum_tag(self.resultatMedite.getListeRemplacementsT1(),da), self.__sum_tag(self.resultatMedite.getListeRemplacementsT2(),da), self.__sum_tag(self.resultatMedite.getListeDeplacementsT1(),da), self.__sum_tag(self.resultatMedite.getListeDeplacementsT2(),da), self.__sum_tag(self.resultatMedite.getBlocsCommunsT1(),da, False), self.__sum_tag(self.resultatMedite.getBlocsCommunsT2(),da, False)]) freqTexts = Numeric.array( [self.__sum_tag(self.__filtre(la,0,self.resultatMedite.getLgSource()),da), self.__sum_tag(self.__filtre(la,self.resultatMedite.getLgSource(),len(self.resultatMedite.getTextesConcatenes())),da)]) fm = TagFrequencyMatrix(freqGeneticModifs,freqTexts) fm.setRelation([0,2,4,6],0) fm.setRelation([1,3,5,7],1) print freqGeneticModifs #print freqGeneticModifs[5] return fm def __sum_tag(self,liste,da,p=False): """ Prend une liste [(deb,fin)] et renvoie un array des fréquences des tags dans celle-ci pre: isinstance(da,dict) isinstance(liste,list) forall([x in liste], isintance(x[0],int) and isinstance(x[1],int)) post: forall([0<=__return__[i]<=len(liste) for i in arrayrange(__return__)]) """ tab = Numeric.zeros(self.tm.getNbItems()) # tableau des fréquences initialisé à 0 for inter in liste: if p: print self.resultatMedite.getTextesConcatenes()[inter[0]:inter[1]] print inter pos = inter[0] while pos < inter[1]: if da.has_key(pos): (fin,tag) = da[pos] #if fin <= inter[1]:# on incrémente que si le mot appartient à l'intervalle tab[self.tm.itemToPos(tag)]+=1 if p: print str(da[pos])+ ' ajouté' #else: assert fin >= inter[1] pos = fin #+= fin-inter[0] # on décale de la longueur du mot else: pos += 1 return tab def __filtre(self,liste,deb,fin): """ Renvoie la sous-liste des items de liste compris entre deb et fin """ res=[] for x in liste: if deb <= x[0] < fin: res.append(x) return res def run(self): """post: assert_(isinstance(__return__,FrequencyMatrix))""" la = self.alignement() da = self.post_traitement_alignement(la) fm = self.calcul_frequences(la,da) return fm class FrequencyMatrix(object): """ Matrice de fréquences """ def __init__(self,nbLine,nbCol): """ pre: isinstance(nbLine,int) and isinstance(nbCol,int) and nbLine>0 and nbCol>0 """ self.freqGeneticModifs = Numeric.array([[0]*nbCol]*nbLine) self.tm = TagManager() self.potm = PartOfTextManager() self.name = 'FrequencyMatrix' def __str__(self): return self.name+'\nfreqGeneticModifs = '+str(self.freqGeneticModifs) def getNbLine(self): """ Nombre total de lignes """ return len(self.freqGeneticModifs) def getNbColumn(self): """ Nombre de colonnes """ return len(self.freqGeneticModifs[0]) def getFreqLine(self,index): """ Renvoie une ligne de fréquence cad une ligne correspondant à une partie de texte """ if isinstance(index,int): return self.freqGeneticModifs[index] else: return self.freqGeneticModifs[self.potm.itemToPos(index)] def getMax(self): """ Renvoie la valeur max sur toute la matrice """ res=0 for i in xrange(self.getNbLine()): for j in self.getFreqLine(i): if j>res: res=j return res def getItemLegend(self): return self.tm def getGraphLegend(self): return self.potm class TagFrequencyMatrix(FrequencyMatrix): """ Matrice de fréquences de tags. En ligne les modifications génétiques et en colonne les tags, self.freqGeneticModifs représentes les fréquences de tags pour chaque type de modif génétique, self.freqTexts représentes les fréquences de tags pour les 2 textes chaque ligne de freqGeneticModifs est en relation avec une ligne de freqTexts """ def __init__(self, freqGeneticModifs, freqTexts): """#pre: isinstance(freqGeneticModifs,Numeric.array) # isinstance(freqTexts,Numeric.array) """ self.freqGeneticModifs = freqGeneticModifs self.freqTexts = freqTexts self.tm = TagManager() self.potm = PartOfTextManager() self.dRelation = {} self.name = 'TagFrequencyMatrix' def __str__(self): return self.name+'\nfreqGeneticModifs = '+str(self.freqGeneticModifs)+ \ '\nfreqTexts = '+str(self.freqTexts) def setRelation(self,posGeneticModifs,posTexts): """Met en relation une partie du texte et un texte, par exemple insertion et texte cible. pre: isinstance(posGeneticModifs,list) isinstance(posTexts,int) """ for pos in posGeneticModifs: self.dRelation[pos] = posTexts def getRelation(self,posGeneticModifs): """pre: isinstance(posGeneticModifs,int) """ try: return self.dRelation[posGeneticModifs] except LookupError: return -1 def getNbLine(self): """ Nombre total de lignes """ return len(self.freqGeneticModifs)+len(self.freqTexts) def getFreqLine(self,index): """ Renvoie une ligne de fréquence cad une ligne correspondant à une partie de texte """ if isinstance(index,int): maxi=len(self.freqGeneticModifs) if index>=maxi: return self.freqTexts[index-maxi] else: return self.freqGeneticModifs[index] else: return self.freqGeneticModifs[self.potm.itemToPos(index)] def getTextLine(self,index): """ Renvoie la ligne de fréquence du texte source ou cible """ if isinstance(index,int): return self.freqTexts[index] def getFreqColumn(self,index): """ Renvoie une colonne d'étiquettes """ if not isinstance(index,int): index = self.potm.itemToPos(index) res=[] for i in xrange(self.freqGeneticModifs.shape()[0]): res.append(self.freqGeneticModifs[i][index]) return Numeric.array(res) def getMaxGenetic(self): """ Renvoie la valeur max sur la matrice de freq genetic""" res=0 for i in xrange(len(self.freqGeneticModifs)): for j in self.getFreqLine(i): if j>res: res=j return res def getMaxText(self): """ Renvoie la valeur max sur la matrice des 2 textes""" res=0 for i in xrange(2): for j in self.getTextLine(i): if j>res: res=j return res class TagFrequencyMatrix2(TagFrequencyMatrix): """ Matrice de fréquences où (Sup,Remp1) sont fusionnés et (Ins,Remp2) aussi """ def __init__(self, fm): """pre: isinstance(fm,FrequencyMatrix) """ self.tm = TagManager() self.potm = PartOfTextManager2() self.freqGeneticModifs = Numeric.array([[0]*fm.getNbColumn()]*4) # 4 lignes #print self.freqGeneticModifs for i in xrange(fm.getNbColumn()): # (Sup + Remp1) self.freqGeneticModifs[0,i] = fm.freqGeneticModifs[0,i] + fm.freqGeneticModifs[2,i] for i in xrange(fm.getNbColumn()): # (Ins + Remp2) self.freqGeneticModifs[1,i] = fm.freqGeneticModifs[1,i] + fm.freqGeneticModifs[3,i] self.freqGeneticModifs[2] = fm.freqGeneticModifs[4] # Dep1 self.freqGeneticModifs[3] = fm.freqGeneticModifs[5] # Dep2 self.freqTexts = fm.freqTexts self.dRelation = {} fm.setRelation([0,2],0) fm.setRelation([1,3],1) self.name = 'TagFrequencyMatrix2' class TagFrequencyMatrix3(TagFrequencyMatrix): """ Matrice de fréquences avec les lignes BC1, BC2, Dep1, Dep2, BC1+Dep1, BC2+Dep2 et Texte1, Texte2 """ def __init__(self, fm): """pre: isinstance(fm,FrequencyMatrix) """ self.tm = TagManager() self.potm = PartOfTextManager3() self.freqGeneticModifs = Numeric.array([[0]*fm.getNbColumn()]*6) # 6 lignes #print self.freqGeneticModifs self.freqGeneticModifs[0] = fm.freqGeneticModifs[6] # BC1 self.freqGeneticModifs[1] = fm.freqGeneticModifs[7] # BC2 self.freqGeneticModifs[2] = fm.freqGeneticModifs[4] # Dep1 self.freqGeneticModifs[3] = fm.freqGeneticModifs[5] # Dep2 for i in xrange(fm.getNbColumn()): # (BC1 + Dep1) self.freqGeneticModifs[4,i] = fm.freqGeneticModifs[6,i] + fm.freqGeneticModifs[4,i] for i in xrange(fm.getNbColumn()): # (BC2 + Dep2) self.freqGeneticModifs[5,i] = fm.freqGeneticModifs[7,i] + fm.freqGeneticModifs[5,i] self.freqTexts = fm.freqTexts self.dRelation = {} fm.setRelation([0,2,4],0) fm.setRelation([1,3,5],1) self.name = 'TagFrequencyMatrix3' class TextFrequencyMatrix(FrequencyMatrix): """ Rapports (Sup+Remp1)/BC1 et (Ins+Remp2)/BC2 en caractères et non en tags """ def __init__(self,res): """ pre: isinstance(res,Donnees.resultatAppli.Resultat) """ FrequencyMatrix.__init__(self,2,2) # 2 lignes * 2 col self.tm = TagManager2() self.potm = PartOfTextManager4() #self.freqGeneticModifs = Numeric.array([[0]*2]*2) # 2 lignes * 2 col for (d,f) in res.getListeSuppressions()+res.getListeRemplacementsT1(): self.freqGeneticModifs[0,0] += f-d for (d,f) in res.getBlocsCommunsT1(): self.freqGeneticModifs[0,1] += f-d for (d,f) in res.getListeInsertions()+res.getListeRemplacementsT2(): self.freqGeneticModifs[1,0] += f-d for (d,f) in res.getBlocsCommunsT2(): self.freqGeneticModifs[1,1] += f-d self.name = 'TextFrequencyMatrix' class Bloc(object): """Bloc décrivant une partie de texte Les propriétés sont en lecture seule -> Bloc n'est pas mutable.""" def __init__(self, type_, debut, fin, listeDeplacements=[]): assert type_ in ['BC','I','S','R'], "Unauthorized type for Bloc: "+type_ self._end_init(type_, debut, fin, listeDeplacements) def _end_init(self, type_, debut, fin, listeDeplacements): """Fin de l'initialisation""" self.type = type_ # Type du bloc assert 0 <= debut < fin, "Invalid Bloc limits" self.debut = debut # Début du bloc self.fin = fin # Fin du bloc if __debug__ and len(listeDeplacements) > 0: assert debut <= listeDeplacements[0][0] < listeDeplacements[-1][1] <= fin, "Moves outside Bloc limits" for d in listeDeplacements: assert isinstance(d, list),str(type(d))+str(d) self.lDep = listeDeplacements # Liste des déplacements inclus dans le bloc def __str__(self): return ''.join(['Bloc(',self.type,',',str(self.debut),',', str(self.fin),',',str(self.lDep),')']) #def getType(self): return self._type #type = property(getType, doc='Type du bloc') #def getDebut(self): return self._debut #debut = property(getDebut, doc='Début du bloc') #def getFin(self): return self._fin #fin = property(getFin, doc='Fin du bloc') #def getLD(self): return self._lDep #def setLD(self, value): # if len(value) > 0: # assert debut <= value[0][0] < value[-1][1] <= fin # self.__lDep = value #lDep = property(getLD, doc='Liste des déplacements inclus dans le bloc') #def getLongueur(self): return self.getFin() - self.getDebut() def getLongueur(self): return self.fin - self.debut longueur = property(getLongueur, doc='Longueur du bloc') def getLongueurDep(self): res = 0 for (d,f) in self.lDep: res += f - d return res longueur_deplacement = property(getLongueurDep, doc='Longueur totale des deplacements') class BlocWD(Bloc): """Bloc où le type D est permis""" def __init__(self, type_, debut, fin, listeDeplacements=[]): assert type_ in ['BC','I','S','R','D'], "Unauthorized type for BlocWD: "+type_ self._end_init(type_, debut, fin, listeDeplacements) def getLongueurDep(self): """Si le bloc est D alors pas besoin de voir sa liste de déplacements""" if self.type == 'D': return self.longueur for (d,f) in self.lDep: res += f - d return res class BiBlocList__(object): """ Construit une liste de Bibloc Un Bibloc est un tuplet de 2 Bloc alignés. Un Bloc est un objet (type,début,fin,listeDep) ou None si il est vide. type est soit I,S,R,BC debut et fin sont les limites du bloc dans la chaine de texte. listeDep est une liste éventuellement vide listant tous les intervalles de déplacement compris dans le bloc. Les blocs I et S sont alignés forcément avec des blocs None. Les blocs R et BC sont alignés forcément avec des blocs respectivement R et BC. """ def __init__(self,resultat,planTravail,depOrdonnes=True): """ Constructeur Si on utilise l'ancien algo d'identification des remplacements et déplacements, on peut avoir des blocs présents uniquement dans resultat.getListeDeplacements(). Ceux-ci sont alors ajoutés comme des S ou des I. dd: si depOrdonnes=False, pas d'assertion d'ordre sur les déplacement-> recherche d'un dep en O(n) dans __decoreDep1() sinon si depOrdonnes=True, assertion d'ordre respectée -> recherche en O(log n) dans __decoreDep2() pre: isinstance(resultat,Donnees.resultatAppli.Resultat) isinstance(planTravail,Donnees.planTravail.PlanTravail) """ self.depOrdonnes = depOrdonnes #def gg(liste): # if len(liste)>0: return str(liste[0]) # else: return '' self.texte = resultat.getTextesConcatenes() self.lgSource = resultat.getLgSource() self.planTravail = planTravail # sert seulement à l'affichage du rapport liste = [] lBCT1 = resultat.getBlocsCommunsT1() lBCT2 = resultat.getBlocsCommunsT2() assert len(lBCT1) == len(lBCT2),str(len(lBCT1))+'/'+str(len(lBCT2)) lRempT1 = resultat.getListeRemplacementsT1() lRempT2 = resultat.getListeRemplacementsT2() assert len(lRempT1) == len(lRempT2) lIns = resultat.getListeInsertions() lSup = resultat.getListeSuppressions() lDepT1 = resultat.getListeDeplacementsT1() #; print lDepT1 lDepT2 = resultat.getListeDeplacementsT2() # ; print lDepT2 i=0 len_lBCT1 = len(lBCT1) ; len_lBCT2 = len(lBCT2) ; len_lRempT1 = len(lRempT1) len_lRempT2 = len(lRempT2) ; len_lSup = len(lSup) ; len_lIns = len(lIns) len_lDepT1 = len(lDepT1) ; len_lDepT2 = len(lDepT2) while (len_lBCT1 > 0 or len_lBCT2 > 0 or len_lRempT1 > 0 or len_lRempT2 > 0 or len_lSup > 0 or len_lIns > 0 or len_lDepT1 > 0 or len_lDepT2 > 0): assert len_lBCT1 == len_lBCT2 assert len_lRempT1 == len_lRempT2 #print len_lDepT1,len_lDepT2 c="""print '-----------------------' print len(lSup),len(lRempT1),len(lBCT1),len(lDepT1) print len(lIns),len(lRempT2),len(lBCT2),len(lDepT2) print gg(lSup),gg(lRempT1),gg(lBCT1),gg(lDepT1) print gg(lIns),gg(lRempT2),gg(lBCT2),gg(lDepT2)""" # pour ajouter un bloc sup soit les 2 listes sont vides # soit BC vides et <= dep car dans ce cas le dep sera inclus dans le sup # soit < BC car pas de chevauchement entre sup et dep if (len_lSup > 0 and ((len_lBCT1 == 0 and len_lDepT1 == 0) or (len_lBCT1 == 0 and lSup[0][0] <= lDepT1[0][0]) or (len_lDepT1 == 0 and lSup[0][0] < lBCT1[0][0]) or (len_lBCT1 > 0 and len_lDepT1 > 0 and lSup[0][0] < lBCT1[0][0] and lSup[0][0] <= lDepT1[0][0]))): # ajout sup depInBloc1 = self.__decoreDep(lSup[0], lDepT1) #décoration avec les déplacements liste.append((Bloc('S',lSup[0][0],lSup[0][1],depInBloc1),None)) # ajout du bibloc lSup.pop(0) ; len_lSup -= 1 ; len_lDepT1 -= len(depInBloc1) elif (len_lIns > 0 and ((len_lBCT2 == 0 and len_lDepT2 == 0) or (len_lBCT2 == 0 and lIns[0][0] <= lDepT2[0][0]) or (len_lDepT2 == 0 and lIns[0][0] < lBCT2[0][0]) or (len_lBCT2 > 0 and len_lDepT2 > 0 and lIns[0][0] < lBCT2[0][0] and lIns[0][0] <= lDepT2[0][0]))): # ajout ins depInBloc2 = self.__decoreDep(lIns[0], lDepT2) #décoration avec les déplacements liste.append((None,Bloc('I',lIns[0][0],lIns[0][1],depInBloc2))) # ajout du bibloc lIns.pop(0) ; len_lIns -= 1 ; len_lDepT2 -= len(depInBloc2) # si depT1 < rempT1 et BCT1, ajout dep comme une sup elif (len_lDepT1 > 0 and ((len_lBCT1 == 0 and len_lRempT1 == 0) or (len_lBCT1 == 0 and lDepT1[0][0] < lRempT1[0][0]) or (len_lRempT1 == 0 and lDepT1[0][0] < lBCT1[0][0]) or (len_lBCT1 > 0 and len_lRempT1 > 0 and lDepT1[0][0] < lBCT1[0][0] and lDepT1[0][0] 0 and ((len_lBCT2 == 0 and len_lRempT2 == 0) or (len_lBCT2 == 0 and lDepT2[0][0] < lRempT2[0][0]) or (len_lRempT2 == 0 and lDepT2[0][0] < lBCT2[0][0]) or (len_lBCT2 > 0 and len_lRempT2 > 0 and lDepT2[0][0] < lBCT2[0][0] and lDepT2[0][0] 0 and len_lRempT2 > 0 and ((len_lBCT1 == 0 and len_lBCT2 == 0) or (lRempT1[0][0] < lBCT1[0][0] and lRempT2[0][0] < lBCT2[0][0]))): com="""((len_lBCT1 == 0 and len_lBCT2 == 0 and len_lDepT1 == 0 and len_lDepT2 == 0) or (len_lBCT1 == 0 and len_lBCT2 == 0 and len_lDepT1 == 0 and lRempT2[0][0] <= lDepT2[0][0]) or (len_lBCT1 == 0 and len_lBCT2 == 0 and lRempT1[0][0] <= lDepT1[0][0] and len_lDepT2 == 0) or (len_lBCT1 == 0 and len_lBCT2 == 0 and lRempT1[0][0] <= lDepT1[0][0] and lRempT2[0][0] <= lDepT2[0][0]) or (len_lBCT1 > 0 and len_lBCT2 > 0 and len_lDepT1 == 0 and len_lDepT2 == 0 and lRempT1[0][0] < lBCT1[0][0] and lRempT2[0][0] < lBCT2[0][0]) or (len_lBCT1 > 0 and len_lBCT2 > 0 and len_lDepT1 == 0 and lRempT2[0][0] <= lDepT2[0][0] and lRempT1[0][0] < lBCT1[0][0] and lRempT2[0][0] < lBCT2[0][0]) or (len_lBCT1 > 0 and len_lBCT2 > 0 and lRempT1[0][0] <= lDepT1[0][0] and len_lDepT2 == 0 and lRempT1[0][0] < lBCT1[0][0] and lRempT2[0][0] < lBCT2[0][0]) or (len_lBCT1 > 0 and len_lBCT2 > 0 and len_lDepT1 > 0 and len_lDepT2 > 0 and lRempT1[0][0] < lBCT1[0][0] and lRempT2[0][0] < lBCT2[0][0] ))): # and lRempT1[0][0] <= lDepT1[0][0] and lRempT2[0][0] <= lDepT2[0][0]))): # ajout remp """ depInBloc1 = self.__decoreDep(lRempT1[0], lDepT1) #décoration avec les déplacements depInBloc2 = self.__decoreDep(lRempT2[0], lDepT2) #décoration avec les déplacements liste.append((Bloc('R',lRempT1[0][0],lRempT1[0][1],depInBloc1), Bloc('R',lRempT2[0][0],lRempT2[0][1],depInBloc2))) # ajout du bibloc #print liste[-1][0],liste[-1][1] lRempT1.pop(0) ; len_lRempT1 -= 1 ; len_lDepT1 -= len(depInBloc1) lRempT2.pop(0) ; len_lRempT2 -= 1 ; len_lDepT2 -= len(depInBloc2) # elif len_lDepT1 > 0 and (len_lBCT1 == 0 or lDepT1[0][0] < lBCT1[0][0]): # ajout dep comme une sup # liste.append((Bloc('S',lDepT1[0][0],lDepT1[0][1],[[lDepT1[0][0],lDepT1[0][1]]]),None)) # ajout du bibloc # lDepT1 = lDepT1[1:] # elif len_lDepT2 > 0 and (len_lBCT2 == 0 or lDepT2[0][0] < lBCT2[0][0]): # ajout dep comme une ins # liste.append((None,Bloc('I',lDepT2[0][0],lDepT2[0][1],[[lDepT2[0][0],lDepT2[0][1]]]))) # ajout du bibloc # lDepT2 = lDepT2[1:] else: # ajout BC liste.append((Bloc('BC',lBCT1[0][0],lBCT1[0][1],[]),Bloc('BC',lBCT2[0][0],lBCT2[0][1],[]))) # ajout du bibloc lBCT1.pop(0) ; len_lBCT1 -= 1 lBCT2.pop(0) ; len_lBCT2 -= 1 self.liste = liste # liste des biblocs if __debug__: assert len_lSup == len_lIns == 0 assert len_lRempT1 == len_lRempT2 == 0 assert len_lBCT1 == len_lBCT2 == 0 assert len_lDepT1 == len_lDepT2 == 0 self._testOrdre() self._testNonPerte(resultat) if len(resultat.getListeRemplacements()) == 0: self.evaluation() logging.debug('extractRemplacements()') self.extractRemplacements() def __decoreDep(self, intervalle, lDep): if not self.depOrdonnes: return self.__decoreDep_1(intervalle, lDep) else: return self.__decoreDep_3(intervalle, lDep) def __decoreDep_1(self, intervalle, lDep): """ Extrait de la liste générale des déplacement lDep les déplacements se situant à l'intérieur du bloc Attention !! modifie lDep Comme sur les déplacements on n'a pas d'assertions sur l'ordre, on parcourt à chaque appel de cette fonction toute la liste des déplacements.""" #if len(lDep) == 0: return [],[] if len(lDep) == 0: return [] res = [] nouvelleLDep = [] for [d,f] in lDep: #assert isinstance(d, list),str(type(d))+str(d) if intervalle[0] <= d and f <= intervalle[1] : # déplacement inlcus dans l'intervalle res.append([d,f]) else: nouvelleLDep.append([d,f]) assert len(lDep) == len(nouvelleLDep) + len(res) lDep = nouvelleLDep #return nouvelleLDep,res return res def __decoreDep_2(self, intervalle, lDep): """ Extrait de la liste générale des déplacement lDep les déplacements se situant à l'intérieur du bloc Attention !! modifie lDep et retourne res2 Ici assertion d'ordre sur les dep, recherhe d'un dep en log(n) """ #if len(lDep) == 0: return [],[] if len(lDep) == 0: return [] deb = bisect.bisect(lDep, intervalle[0]) fin = bisect.bisect(lDep, intervalle[1]) assert deb <= fin if deb == fin: # aucun déplacement n'existe dans la liste entre les 2 intervalles #return lDep,[] return [] else: res2 = lDep[deb:fin] lDep[deb:fin] = [] #lDep = lDep[:deb]+lDep[fin:] #return lDep[:deb]+lDep[fin:], lDep[deb:fin] return res2 def __decoreDep_3(self, intervalle, lDep): """ Extrait de la liste générale des déplacement lDep les déplacements se situant à l'intérieur du bloc Attention !! modifie lDep et retourne res2 Ici assertion d'ordre sur les dep, recherhe d'un dep en temps linéaire comme lDep[0] est toujours >= intervalle (parce que l'ordre est maintenu par la fonction appelante), on commence la recherche à partir de là """ if len(lDep) == 0: return [] res2 = [] i = 0 while lDep[0] < intervalle[1] and lDep[1] <= intervalle[1]: i+= 1 res2.append(lDep.pop(0)) # mofifie lDep !! return res2 def _testOrdre(self): """ Teste le bon ordre des blocs dans la liste """ posT1 = 0 # position courante dans le texte source posT2 = self.lgSource # position courante dans le texte cible prevB1 = prevB2 = (0,0,0,[]) for (B1,B2) in self.liste: if B1 is not None: # la position précédente est <= au début du bloc courant assert posT1 <= B1.debut,str(posT1)+' '+str(prevB1)+' '+str(B1) posT1 = B1.fin for dep in B1.lDep:# les déplacements sont bien inclus dans le bloc courant assert B1.debut <= dep[0] <= dep[1] <= B1.fin prevB1 = B1 if B2 is not None: assert posT2 <= B2.debut, str(posT2)+' '+str(prevB2)+' '+str(B2) posT2 = B2.fin for dep in B2.lDep: assert B2.debut <= dep[0] <= dep[1] <= B2.fin prevB2 = B2 def _testNonPerte(self, resultat): """Teste la non-perte de données lors de la création du BiblocList On teste si chaque element dans les listes de la donnée en entrée (param Resultat) est bien présent en sortie dans self.liste """ # BC T1 for (d,f) in resultat.getBlocsCommunsT1(): for (B1,B2) in self.liste: if (B1 is not None and B1.type == 'BC' and B1.debut == d and B1.fin == f): break else: raise AssertionError("Bloc BC1 "+str((d,f))+" lost during BiblocList creation") # BC T2 for (d,f) in resultat.getBlocsCommunsT2(): for (B1,B2) in self.liste: if (B2 is not None and B2.type == 'BC' and B2.debut == d and B2.fin == f): break else: raise AssertionError("Bloc BC2 "+str((d,f))+" lost during BiblocList creation") # Suppressions for (d,f) in resultat.getListeSuppressions(): for (B1,B2) in self.liste: if (B1 is not None and (B1.type == 'S' or B1.type == 'R') and B1.debut == d and B1.fin == f): break else: raise AssertionError("Bloc S "+str((d,f))+" lost during BiblocList creation") # Insertions for (d,f) in resultat.getListeInsertions(): for (B1,B2) in self.liste: if (B2 is not None and (B2.type == 'I' or B2.type == 'R') and B2.debut == d and B2.fin == f): break else: raise AssertionError("Bloc I "+str((d,f))+" lost during BiblocList creation") # Remplacements T1 for (d,f) in resultat.getListeRemplacementsT1(): for (B1,B2) in self.liste: if (B1 is not None and B1.type == 'R' and B1.debut == d and B1.fin == f): break else: raise AssertionError("Bloc R1 "+str((d,f))+" lost during BiblocList creation") # Remplacements T2 for (d,f) in resultat.getListeRemplacementsT2(): for (B1,B2) in self.liste: if (B2 is not None and B2.type == 'R' and B2.debut == d and B2.fin == f): break else: raise AssertionError("Bloc R2 "+str((d,f))+" lost during BiblocList creation") # Dep T1 for (d,f) in resultat.getListeDeplacementsT1(): for (B1,B2) in self.liste: if (B1 is not None and ((B1.type == 'D' and B1.debut == d and B1.fin == f) or ((B1.type == 'S' or B1.type == 'R') and [d,f] in B1.lDep) or (B1.type == 'S' and B1.debut == d and B1.fin == f))): break else: raise AssertionError("Bloc Dep1 "+str((d,f))+" lost during BiblocList creation") # BC T2 for (d,f) in resultat.getListeDeplacementsT2(): for (B1,B2) in self.liste: if (B2 is not None and ((B2.type == 'D' and B2.debut == d and B2.fin == f) or ((B2.type == 'I' or B2.type == 'R') and [d,f] in B2.lDep) or (B2.type == 'I' and B2.debut == d and B2.fin == f))): break else: raise AssertionError("Bloc Dep2 "+str((d,f))+" lost during BiblocList creation") def extractRemplacements(self): """ Recherche les S et I correspondant au critère de transformation en R et les convertit. Convertit chaque paire de bibloc (S,None) et (None,I) se suivant en un bibloc (R,R) Modifie directement self.liste plutôt que de recréer une nouvelle liste ce qui est memory expensive""" if len(self.liste) == 0: return if __debug__: old_liste = self.liste[:] tool = utile.Utile() ratio_min_remplacement = float(100)/self.planTravail.getParam().getp2() i = len(self.liste) - 2 while i >= 0: biBloc = self.liste[i] # bibloc courant biBlocSuiv = self.liste[i+1] # bibloc suivant # on cherche un biblox S et un bibloc I qui se suivent et compatilbes # pour être transformés en (R,R) if (biBloc[0] is not None and biBloc[0].type == 'S' and biBlocSuiv[1] is not None and biBlocSuiv[1].type == 'I' and tool.adequation_remplacement(self.texte[biBloc[0].debut:biBloc[0].fin], self.texte[biBlocSuiv[1].debut:biBlocSuiv[1].fin], ratio_min_remplacement)): self.liste[i:i+2] = [(Bloc('R',biBloc[0].debut,biBloc[0].fin,biBloc[0].lDep), Bloc('R',biBlocSuiv[1].debut,biBlocSuiv[1].fin,biBlocSuiv[1].lDep))] i -= 1 if __debug__: self._testOrdre() # on teste si on n'a perdu aucun elt de l'ancienne liste for (B1,B2) in old_liste: if B1 is not None: for (BN1,BN2) in self.liste: if (BN1 != None and B1.debut == BN1.debut and B1.fin == BN1.fin and ((B1.type == 'S' and (BN1.type == 'S' or BN1.type == 'R') or (B1.type == 'BC' and B1.type == 'BC')))): break else: raise AssertionError, "elt B1 lost"+str(B1)+str(B2) if B2 is not None: for (BN1,BN2) in self.liste: if (BN2 != None and B2.debut == BN2.debut and B2.fin == BN2.fin and ((B2.type == 'I' and (BN2.type == 'I' or BN2.type == 'R') or (B2.type == 'BC' and B2.type == 'BC')))): break else: raise AssertionError, "elt B2 lost"+str(B1)+str(B2) def extractRemplacements__(self): """ Recherche les S et I correspondant au critère de transformation en R et les convertit. Convertit chaque paire de bibloc (S,None) et (None,I) se suivant en un bibloc (R,R) """ if len(self.liste) == 0: return tool = utile.Utile() ratio_min_remplacement = float(100)/self.planTravail.getParam().getp2() nouvelleListe = [] dernierAjout = 'bloc' for i in xrange(len(self.liste)-1): biBloc = self.liste[i] # bibloc courant biBlocSuiv = self.liste[i+1] # bibloc suivant # on cherche un biblox S et un bibloc I qui se suivent et compatilbes # pour être transformés en (R,R) if (biBloc[0] is not None and biBloc[0].type == 'S' and biBlocSuiv[1] is not None and biBlocSuiv[1].type == 'I' and tool.adequation_remplacement(self.texte[biBloc[0].debut:biBloc[0].fin], self.texte[biBlocSuiv[1].debut:biBlocSuiv[1].fin], ratio_min_remplacement)): nouvelleListe.append((Bloc('R',biBloc[0].debut,biBloc[0].fin,biBloc[0].lDep), Bloc('R',biBlocSuiv[1].debut,biBlocSuiv[1].fin,biBlocSuiv[1].lDep))) dernierAjout = 'R' # ce bibloc vient d'être transformé en R elif (biBloc[1] is not None and biBloc[1].type == 'I' and dernierAjout == 'R'): dernierAjout = 'bloc' else: nouvelleListe.append(biBloc) dernierAjout = 'bloc' if dernierAjout == 'bloc': nouvelleListe.append(self.liste[-1]) old_liste = self.liste self.liste = nouvelleListe if __debug__: self._testOrdre() # on teste si on n'a perdu aucun elt de l'ancienne liste for (B1,B2) in old_liste: if B1 is not None: for (BN1,BN2) in self.liste: if (BN1 != None and B1.debut == BN1.debut and B1.fin == BN1.fin and ((B1.type == 'S' and (BN1.type == 'S' or BN1.type == 'R') or (B1.type == 'BC' and B1.type == 'BC')))): break else: raise AssertionError, "elt B1 lost"+str(B1)+str(B2) if B2 is not None: for (BN1,BN2) in self.liste: if (BN2 != None and B2.debut == BN2.debut and B2.fin == BN2.fin and ((B2.type == 'I' and (BN2.type == 'I' or BN2.type == 'R') or (B2.type == 'BC' and B2.type == 'BC')))): break else: raise AssertionError, "elt B2 lost"+str(B1)+str(B2) def toResultat(self): """ Transfomre la liste de biblocs en un Resultat Attention !! la liste des PAIRES de blocs déplacés n'est pas remplie """ supp = []; ins = []; rempT1 = []; rempT2 = [] BCT1 = [];BCT2 = []; depT1 = []; depT2 = [] for (B1,B2) in self.liste: # parcours toute la liste de biblocs if B1 is not None: # suivant le type de B1, l'ajoute dans la bonne liste B1_type = B1.type if B1_type == 'S': supp.append([B1.debut,B1.fin]) elif B1_type == 'R': rempT1.append([B1.debut,B1.fin]) elif B1_type == 'D': depT1.append([B1.debut,B1.fin]) else: BCT1.append([B1.debut,B1.fin]) depT1.extend(B1.lDep) if B2 is not None:# suivant le type de B2, l'ajoute dans la bonne liste B2_type = B2.type if B2_type == 'I': ins.append([B2.debut,B2.fin]) elif B2_type == 'R': rempT2.append([B2.debut,B2.fin]) elif B2_type == 'D': depT2.append([B2.debut,B2.fin]) else: BCT2.append([B2.debut,B2.fin]) depT2.extend(B2.lDep) # on extend pour former les listes des 2 fichiers pour éviter d'utliser # la concaténation de liste qui crée une nouvelle liste depT1.extend(depT2) ; del depT2 rempT1.extend(rempT2) ; del rempT2 BCT1.extend(BCT2) ; del BCT2 return Donnees.resultatAppli.Resultat(ins, supp, depT1, rempT1, self.lgSource, self.texte, BCT1, []) def evaluation(self): """Evalue l'alignement""" seq1 = self.lgSource seq2 = len(self.texte) - seq1 ins = sup = remp1 = remp2 = bc1 = bc2 = dep1 = dep2 = 0.0 for (B1,B2) in self.liste: if B1 is not None: B1_type = B1.type if B1_type == 'S': sup += B1.longueur elif B1_type == 'R': remp1 += B1.longueur elif B1_type == 'BC': bc1 += B1.longueur if B1_type == 'D': dep1 += B1.longueur else: dep1 += B1.longueur_deplacement if B2 is not None: B2_type = B2.type if B2_type == 'I': ins += B2.longueur elif B2_type == 'R': remp2 += B2.longueur elif B2_type == 'BC': bc2 += B2.longueur if B2_type == 'D': dep2 += B2.longueur else: dep2 += B2.longueur_deplacement #if self.planTravail.getParam().get assert bc1 == bc2,str(bc1)+' '+str(bc2) formules = ['(bc1 + bc2)', '(dep1 + dep2)', '(bc1 + bc2) / (seq1 + seq2)', '(dep1 + dep2) / (seq1 + seq2)', '(bc1 + bc2 - dep1 - dep2)', '(bc1 + bc2 - dep1 - dep2) / (seq1 + seq2)', '(bc1 + bc2 - sup - ins - remp1 - remp2)', '(bc1 + bc2 - sup - ins - remp1 - remp2) / (seq1 + seq2)', '(bc1 + bc2 - sup - ins - remp1 - remp2 - dep1 - dep2)', '(bc1 + bc2 - sup - ins - remp1 - remp2 - dep1 - dep2) / (seq1 + seq2)', #'(sup + ins + remp1 + remp2 + dep1 + dep2)', #'(sup + ins + remp1 + remp2 + dep1 + dep2) / (seq1 + seq2)' ] #res = '' for f in formules: #res += f + ' = ' + str(round(eval(f),4)) + '\n' logging.info(f + ' = ' + str(round(eval(f),4))) #logging.info( ins, sup, remp1, remp2, bc1, bc2, dep1, dep2) #print res def print_html(self, dossierOutput=None): """ Imprime un rapport html à partir de la liste de biblocs dossierOutput: dossier où écrire le fichier HTML """ if len(self.liste) > 10: self.print_html_streaming(dossierOutput) else: self.print_html_oneshot(dossierOutput) def print_html_streaming(self, dossierOutput=None): """ Imprime un rapport html en plusieurs fois pour éviter de construire toute la chaine à substituer en mémoire dossierOutput: dossier où écrire le fichier HTML """ # ouverture du template ne contenant que le début du raport template = os.path.join(Utile.constantesDonnees.REPPRIVE,"template_rapport_stream.html") ftemplate = open(template,'r') stemplate = ''.join(ftemplate.readlines()) dgm = Controleurs.DGManager.DGManager() s = Template(stemplate) # substitution des variables sres = s.safe_substitute( FILE1 = dgm.getEtatPath(self.planTravail.getAuteur(), self.planTravail.getOeuvre(),self.planTravail.getVersionSource(),self.planTravail.getEtatSource()), FILE2 = dgm.getEtatPath(self.planTravail.getAuteur(), self.planTravail.getOeuvre(),self.planTravail.getVersionCible(),self.planTravail.getEtatCible()), PARAM_PIVOTS = self.planTravail.getParam().getp1(), RATIO_REMPLACEMENTS = self.planTravail.getParam().getp2(), SEUIL_DEPLACEMENTS = self.planTravail.getParam().getp3(), PARAM_CASSE = self.__paramToON(self.planTravail.getParam().getp5()), PARAM_SEPARATEURS = self.__paramToON(self.planTravail.getParam().getp6()), PARAM_DIACRITIQUES = self.__paramToON(self.planTravail.getParam().getp7())) # écriture du rapport if dossierOutput is not None: chemin = os.path.join(dossierOutput,"rapport.html") else: chemin = os.path.join(constantes.REPMEDITE,"rapport.html") fres = open(chemin,'w') fres.write(sres) # écriture de la première partie # ecriture en streaming de la table self.__listeToHtmlTable(stream=True, fileBuffer=fres) fres.write('

') fres.close() def print_html_oneshot(self, dossierOutput=None): """ Imprime un rapport html en une seule fois dossierOutput: dossier où écrire le fichier HTML """ # ouverture du template template = os.path.join(Utile.constantesDonnees.REPPRIVE,"template_rapport.html") ftemplate = open(template,'r') stemplate = ''.join(ftemplate.readlines()) dgm = Controleurs.DGManager.DGManager() s = Template(stemplate) # substitution des variables sres = s.safe_substitute( FILE1 = dgm.getEtatPath(self.planTravail.getAuteur(), self.planTravail.getOeuvre(),self.planTravail.getVersionSource(),self.planTravail.getEtatSource()), FILE2 = dgm.getEtatPath(self.planTravail.getAuteur(), self.planTravail.getOeuvre(),self.planTravail.getVersionCible(),self.planTravail.getEtatCible()), PARAM_PIVOTS = self.planTravail.getParam().getp1(), RATIO_REMPLACEMENTS = self.planTravail.getParam().getp2(), SEUIL_DEPLACEMENTS = self.planTravail.getParam().getp3(), PARAM_CASSE = self.__paramToON(self.planTravail.getParam().getp5()), PARAM_SEPARATEURS = self.__paramToON(self.planTravail.getParam().getp6()), PARAM_DIACRITIQUES = self.__paramToON(self.planTravail.getParam().getp7()), TABLE=self.__listeToHtmlTable()) # écriture du rapport if dossierOutput is not None: chemin = os.path.join(dossierOutput,"rapport.html") else: chemin = os.path.join(constantes.REPMEDITE,"rapport.html") fres = open(chemin,'w') fres.write(sres) fres.close() def __paramToON(self,param): """ Renvoie 'Oui' ou 'Non' en fonction d'un param booléen """ if param: return "Oui" else: return "Non" def __listeToHtmlTable(self, stream=False, fileBuffer=None): """ Convertit la liste de BiBlocs en une table html Chaque Bibloc est convertit en une ligne d'une table html Si stream, on ecrit régulièrement dans fileBuffer la table courante et on la réinitialise ensuite sinon on crée une grosse chaine que l'on renvoie""" assert stream==False or (stream and fileBuffer is not None) res = [] ; i = 0 for (B1,B2) in self.liste: res.append('')# += "" # début de ligne # colonne gauche if B1 is None: res.append('') # += "" # bloc vide else: B1_type = B1.type if B1_type == 'S': res.extend(['',self.__souligneTexte(B1),'']) # supp elif B1_type == 'R': res.extend([' ',self.__souligneTexte(B1),'']) # remp elif B1_type == 'D': res.extend(['',self.__souligneTexte(B1),'']) # dep else: res.extend(['',self.__keepMEP(self.texte[B1.debut:B1.fin]),'']) # BC # colonne droite if B2 is None: res.append('') # bloc vide else: B2_type = B2.type if B2_type == 'I': res.extend(['',self.__souligneTexte(B2),'']) #ins elif B2_type == 'R': res.extend(['',self.__souligneTexte(B2),'']) # remp elif B2_type == 'D': res.extend(['',self.__souligneTexte(B2),'']) # dep else: res.extend(['',self.__keepMEP(self.texte[B2.debut:B2.fin]),'']) # BC res.append('\n') # fin de ligne if stream and i%50 == 0: fileBuffer.write(''.join(res)) res = [] if stream: fileBuffer.write(''.join(res)) res = [] else: return ''.join(res) def __souligneTexte(self,bloc): """ Renvoie une chaine html avec le texte souligné aux caractères déplacés """ if bloc.type == 'D': return (''+ self.__keepMEP(self.texte[bloc.debut:bloc.fin])+'') res = "" deb = i = bloc.debut fin = bloc.fin lDep = bloc.lDep[:] # on copie pour ne pas modifier la liste originale # on parcours tout le bloc pour chercher les déplacements à l'intérieur de celui-ci while i < fin: # si le caractère courant est le début d'un déplacement # <= (au lieu de ==) à cause des chevauchements de déplacements du genre ('I', 5221, 5239, [(5224, 5230), (5226, 5231), (5236, 5239)]) if len(lDep) > 0 and lDep[0][0] <= i: res += ''+self.__keepMEP(self.texte[i:lDep[0][1]])+'' i = lDep[0][1] lDep.pop(0) elif len(lDep) > 0 and lDep[0][0] > i: # si on est sur du texte normal res += self.__keepMEP(self.texte[i:lDep[0][0]]) i = lDep[0][0] else: # si pas ou plus de déplacement assert len(lDep)==0 res += self.__keepMEP(self.texte[i:fin]) i = fin return res def __keepMEP(self, texte): """ Fonction chargée de conserver la mise en page du texte original Remplace les retours à la ligne par des
et les espaces par des   Le remplacement des espaces par des nbsp est très utile pour visulaiser des alignements de code source mais plus discutable pour de la langue nat. De même mais de façon moins importante pour les br.""" return texte res = "" for i in xrange(len(texte)): if texte[i] in '\r\n': res += '
' #elif texte[i] in ' ': res += ' ' else: # remplace tous les caractères spéciaux par leur code html comme   try: res += '&' + htmlentitydefs.codepoint2name[ord(texte[i])] + ';' except KeyError: res += texte[i] return res class BiBlocListWD__(BiBlocList__): """BiblocList avec type déplacement (D) autorisé """ def __init__(self,resultat,planTravail,depOrdonnes=True): BiBlocList.__init__(self,resultat,planTravail,depOrdonnes) self.evaluation() logging.debug('extractDeplacements()') self.extractDeplacements() self.evaluation() def extractDeplacements(self): """ Extraction des déplacements Teste les blocs insérés et supprimés. Si le rapport des déplacements à l'intérieur d'un bloc est supérieur au seuil Alors ce bloc est scindé en une liste de blocs (I ou S) et D Modifie directement self.liste""" tool = utile.Utile() ratio_seuil_lissage = float(self.planTravail.getParam().getp3()) /100 #nouvelleListe = [] i = len(self.liste) - 1 while i >= 0: (B1,B2) = self.liste[i] if (B1 is not None and B1.type == 'S'): # bloc S assert B2 is None supMoinsDep = tool.soustr_l_intervalles([[B1.debut,B1.fin]], B1.lDep) # bloc S moins les dep ratio_lissage = float(tool.longueur(supMoinsDep))/(B1.fin-B1.debut) # ratio du bloc if ratio_lissage <= ratio_seuil_lissage: self.liste[i:i+1] = self.__extractDepInsSup(supMoinsDep,B1.lDep,'S') elif (B2 is not None and B2.type == 'I'):# bloc I assert B1 is None insMoinsDep = tool.soustr_l_intervalles([[B2.debut,B2.fin]], B2.lDep) ratio_lissage = float(tool.longueur(insMoinsDep))/(B2.fin-B2.debut) if ratio_lissage <= ratio_seuil_lissage: self.liste[i:i+1] = self.__extractDepInsSup(insMoinsDep,B2.lDep,'I') i -= 1 if __debug__: self._testOrdre() def extractDeplacements__old(self): """ Extraction des déplacements Teste les blocs insérés et supprimés. Si le rapport des déplacements à l'intérieur d'un bloc est supérieur au seuil Alors ce bloc est scindé en une liste de blocs (I ou S) et D""" tool = utile.Utile() ratio_seuil_lissage = float(self.planTravail.getParam().getp3()) /100 nouvelleListe = [] for (B1,B2) in self.liste: if (B1 is not None and B1.type == 'S'): # bloc S assert B2 is None supMoinsDep = tool.soustr_l_intervalles([[B1.debut,B1.fin]], B1.lDep) # bloc S moins les dep ratio_lissage = float(tool.longueur(supMoinsDep))/(B1.fin-B1.debut) # ratio du bloc if ratio_lissage > ratio_seuil_lissage: nouvelleListe.append((B1,None)) else: nouvelleListe.extend(self.__extractDepInsSup(supMoinsDep,B1.lDep,'S')) elif (B2 is not None and B2.type == 'I'):# bloc I assert B1 is None insMoinsDep = tool.soustr_l_intervalles([[B2.debut,B2.fin]], B2.lDep) ratio_lissage = float(tool.longueur(insMoinsDep))/(B2.fin-B2.debut) if ratio_lissage > ratio_seuil_lissage: nouvelleListe.append((None,B2)) else: nouvelleListe.extend(self.__extractDepInsSup(insMoinsDep,B2.lDep,'I')) else: # autres blocs: R et BC nouvelleListe.append((B1,B2)) self.liste = nouvelleListe if __debug__: self._testOrdre() def __extractDepInsSup(self,lSupOrIns,listeDep,SorI): """On scinde effectivement le blocs en une liste de blocs (S ou I) et D lSupOrIns: liste de (I ou S) listeDep: liste de D SorI: traite-on des S ou des I ? pre: isinstance(lSupOrIns,list) and isinstance(listeDep,list) (SorI == 'S' or SorI == 'I') """ nouvelleListe = [] len_listeDep = len(listeDep) prevdeb = nbDep = 0 while len(lSupOrIns) > 0 or len(listeDep) > 0: # on a ajouté tous les D, on peut ajouter le reste des (I ou S) if len(listeDep) == 0: for (deb,fin) in lSupOrIns: # pour chaque bloc (I ou S) assert prevdeb <= deb # assertion d'ordre prevdeb = deb if SorI == 'S': nouvelleListe.append((Bloc('S',deb,fin,[]),None)) # ajout effectif else: nouvelleListe.append((None,Bloc('I',deb,fin,[]))) lSupOrIns = [] # on a ajouté tous les (I ou S), on peut ajouter les reste des D elif len(lSupOrIns) == 0: for (deb,fin) in listeDep: # pour chaque bloc D assert prevdeb <= deb prevdeb = deb if SorI == 'S': nouvelleListe.append((BlocWD('D',deb,fin,[]),None)) else: nouvelleListe.append((None,BlocWD('D',deb,fin,[]))) nbDep += 1 listeDep = [] # si bloc courant (I ou S) <= bloc courant D alors on l'ajoute elif lSupOrIns[0][0] <= listeDep[0][0]: assert prevdeb <= lSupOrIns[0][0] prevdeb = lSupOrIns[0][0] if SorI == 'S': nouvelleListe.append((Bloc('S',lSupOrIns[0][0],lSupOrIns[0][1],[]),None)) else: nouvelleListe.append((None,Bloc('I',lSupOrIns[0][0],lSupOrIns[0][1],[]))) #lSupOrIns = lSupOrIns[1:] lSupOrIns.pop(0) else: assert prevdeb <= listeDep[0][0] prevdeb = listeDep[0][0] if SorI == 'S': nouvelleListe.append((BlocWD('D',listeDep[0][0],listeDep[0][1],[]),None)) else: nouvelleListe.append((None,BlocWD('D',listeDep[0][0],listeDep[0][1],[]))) listeDep.pop(0) nbDep += 1 assert len(listeDep) == len(lSupOrIns) == 0 # les 2 listes ont du etre traitées entièrement assert nbDep == len_listeDep return nouvelleListe class BiBlocList(object): """ Construit une liste de Bibloc Un Bibloc est un tuplet de 2 Bloc alignés. Un Bloc est un objet (type,début,fin,listeDep) ou None si il est vide. type est soit I,S,R,BC debut et fin sont les limites du bloc dans la chaine de texte. listeDep est une liste éventuellement vide listant tous les intervalles de déplacement compris dans le bloc. Les blocs I et S sont alignés forcément avec des blocs None. Les blocs R et BC sont alignés forcément avec des blocs respectivement R et BC. """ def __init__(self,resultat,planTravail,depOrdonnes=True): """ Constructeur Si on utilise l'ancien algo d'identification des remplacements et déplacements, on peut avoir des blocs présents uniquement dans resultat.getListeDeplacements(). Ceux-ci sont alors ajoutés comme des S ou des I. dd: si depOrdonnes=False, pas d'assertion d'ordre sur les déplacement-> recherche d'un dep en O(n) dans __decoreDep1() sinon si depOrdonnes=True, assertion d'ordre respectée -> recherche en O(log n) dans __decoreDep2() pre: isinstance(resultat,Donnees.resultatAppli.Resultat) isinstance(planTravail,Donnees.planTravail.PlanTravail) """ self.depOrdonnes = depOrdonnes #def gg(liste): # if len(liste)>0: return str(liste[0]) # else: return '' self.texte = resultat.getTextesConcatenes() self.lgSource = resultat.getLgSource() self.planTravail = planTravail # sert seulement à l'affichage du rapport liste = [] lBCT1 = resultat.getBlocsCommunsT1() lBCT2 = resultat.getBlocsCommunsT2() assert len(lBCT1) == len(lBCT2),str(len(lBCT1))+'/'+str(len(lBCT2)) lRempT1 = resultat.getListeRemplacementsT1() lRempT2 = resultat.getListeRemplacementsT2() assert len(lRempT1) == len(lRempT2) lIns = resultat.getListeInsertions() lSup = resultat.getListeSuppressions() lDepT1 = resultat.getListeDeplacementsT1() #; print lDepT1 lDepT2 = resultat.getListeDeplacementsT2() # ; print lDepT2 i=0 len_lBCT1 = len(lBCT1) ; len_lBCT2 = len(lBCT2) ; len_lRempT1 = len(lRempT1) len_lRempT2 = len(lRempT2) ; len_lSup = len(lSup) ; len_lIns = len(lIns) len_lDepT1 = len(lDepT1) ; len_lDepT2 = len(lDepT2) while (len_lBCT1 > 0 or len_lBCT2 > 0 or len_lRempT1 > 0 or len_lRempT2 > 0 or len_lSup > 0 or len_lIns > 0 or len_lDepT1 > 0 or len_lDepT2 > 0): assert len_lBCT1 == len_lBCT2 assert len_lRempT1 == len_lRempT2 #if i%1000==0: logging.debug('itération %d',i) i += 1 #print len_lDepT1,len_lDepT2 c="""print '-----------------------' print len(lSup),len(lRempT1),len(lBCT1),len(lDepT1) print len(lIns),len(lRempT2),len(lBCT2),len(lDepT2) print gg(lSup),gg(lRempT1),gg(lBCT1),gg(lDepT1) print gg(lIns),gg(lRempT2),gg(lBCT2),gg(lDepT2)""" # pour ajouter un bloc sup soit les 2 listes sont vides # soit BC vides et <= dep car dans ce cas le dep sera inclus dans le sup # soit < BC car pas de chevauchement entre sup et dep if (len_lSup > 0 and ((len_lBCT1 == 0 and len_lDepT1 == 0) or (len_lBCT1 == 0 and lSup[0][0] <= lDepT1[0][0]) or (len_lDepT1 == 0 and lSup[0][0] < lBCT1[0][0]) or (len_lBCT1 > 0 and len_lDepT1 > 0 and lSup[0][0] < lBCT1[0][0] and lSup[0][0] <= lDepT1[0][0]))): # ajout sup depInBloc1 = self.__decoreDep(lSup[0], lDepT1) #décoration avec les déplacements liste.append((('S',lSup[0][0],lSup[0][1],depInBloc1),None)) # ajout du bibloc lSup.pop(0) ; len_lSup -= 1 ; len_lDepT1 -= len(depInBloc1) elif (len_lIns > 0 and ((len_lBCT2 == 0 and len_lDepT2 == 0) or (len_lBCT2 == 0 and lIns[0][0] <= lDepT2[0][0]) or (len_lDepT2 == 0 and lIns[0][0] < lBCT2[0][0]) or (len_lBCT2 > 0 and len_lDepT2 > 0 and lIns[0][0] < lBCT2[0][0] and lIns[0][0] <= lDepT2[0][0]))): # ajout ins depInBloc2 = self.__decoreDep(lIns[0], lDepT2) #décoration avec les déplacements liste.append((None,('I',lIns[0][0],lIns[0][1],depInBloc2))) # ajout du bibloc lIns.pop(0) ; len_lIns -= 1 ; len_lDepT2 -= len(depInBloc2) # si depT1 < rempT1 et BCT1, ajout dep comme une sup elif (len_lDepT1 > 0 and ((len_lBCT1 == 0 and len_lRempT1 == 0) or (len_lBCT1 == 0 and lDepT1[0][0] < lRempT1[0][0]) or (len_lRempT1 == 0 and lDepT1[0][0] < lBCT1[0][0]) or (len_lBCT1 > 0 and len_lRempT1 > 0 and lDepT1[0][0] < lBCT1[0][0] and lDepT1[0][0] 0 and ((len_lBCT2 == 0 and len_lRempT2 == 0) or (len_lBCT2 == 0 and lDepT2[0][0] < lRempT2[0][0]) or (len_lRempT2 == 0 and lDepT2[0][0] < lBCT2[0][0]) or (len_lBCT2 > 0 and len_lRempT2 > 0 and lDepT2[0][0] < lBCT2[0][0] and lDepT2[0][0] 0 and len_lRempT2 > 0 and ((len_lBCT1 == 0 and len_lBCT2 == 0) or (lRempT1[0][0] < lBCT1[0][0] and lRempT2[0][0] < lBCT2[0][0]))): com="""((len_lBCT1 == 0 and len_lBCT2 == 0 and len_lDepT1 == 0 and len_lDepT2 == 0) or (len_lBCT1 == 0 and len_lBCT2 == 0 and len_lDepT1 == 0 and lRempT2[0][0] <= lDepT2[0][0]) or (len_lBCT1 == 0 and len_lBCT2 == 0 and lRempT1[0][0] <= lDepT1[0][0] and len_lDepT2 == 0) or (len_lBCT1 == 0 and len_lBCT2 == 0 and lRempT1[0][0] <= lDepT1[0][0] and lRempT2[0][0] <= lDepT2[0][0]) or (len_lBCT1 > 0 and len_lBCT2 > 0 and len_lDepT1 == 0 and len_lDepT2 == 0 and lRempT1[0][0] < lBCT1[0][0] and lRempT2[0][0] < lBCT2[0][0]) or (len_lBCT1 > 0 and len_lBCT2 > 0 and len_lDepT1 == 0 and lRempT2[0][0] <= lDepT2[0][0] and lRempT1[0][0] < lBCT1[0][0] and lRempT2[0][0] < lBCT2[0][0]) or (len_lBCT1 > 0 and len_lBCT2 > 0 and lRempT1[0][0] <= lDepT1[0][0] and len_lDepT2 == 0 and lRempT1[0][0] < lBCT1[0][0] and lRempT2[0][0] < lBCT2[0][0]) or (len_lBCT1 > 0 and len_lBCT2 > 0 and len_lDepT1 > 0 and len_lDepT2 > 0 and lRempT1[0][0] < lBCT1[0][0] and lRempT2[0][0] < lBCT2[0][0] ))): # and lRempT1[0][0] <= lDepT1[0][0] and lRempT2[0][0] <= lDepT2[0][0]))): # ajout remp """ depInBloc1 = self.__decoreDep(lRempT1[0], lDepT1) #décoration avec les déplacements depInBloc2 = self.__decoreDep(lRempT2[0], lDepT2) #décoration avec les déplacements liste.append((('R',lRempT1[0][0],lRempT1[0][1],depInBloc1), ('R',lRempT2[0][0],lRempT2[0][1],depInBloc2))) # ajout du bibloc #print liste[-1][0],liste[-1][1] lRempT1.pop(0) ; len_lRempT1 -= 1 ; len_lDepT1 -= len(depInBloc1) lRempT2.pop(0) ; len_lRempT2 -= 1 ; len_lDepT2 -= len(depInBloc2) # elif len_lDepT1 > 0 and (len_lBCT1 == 0 or lDepT1[0][0] < lBCT1[0][0]): # ajout dep comme une sup # liste.append((Bloc('S',lDepT1[0][0],lDepT1[0][1],[[lDepT1[0][0],lDepT1[0][1]]]),None)) # ajout du bibloc # lDepT1 = lDepT1[1:] # elif len_lDepT2 > 0 and (len_lBCT2 == 0 or lDepT2[0][0] < lBCT2[0][0]): # ajout dep comme une ins # liste.append((None,Bloc('I',lDepT2[0][0],lDepT2[0][1],[[lDepT2[0][0],lDepT2[0][1]]]))) # ajout du bibloc # lDepT2 = lDepT2[1:] else: # ajout BC liste.append((('BC',lBCT1[0][0],lBCT1[0][1],[]),('BC',lBCT2[0][0],lBCT2[0][1],[]))) # ajout du bibloc lBCT1.pop(0) ; len_lBCT1 -= 1 lBCT2.pop(0) ; len_lBCT2 -= 1 self.liste = liste # liste des biblocs if False and __debug__: assert len_lSup == len_lIns == 0 assert len_lRempT1 == len_lRempT2 == 0 assert len_lBCT1 == len_lBCT2 == 0 assert len_lDepT1 == len_lDepT2 == 0 self._testOrdre() self._testNonPerte(resultat) if len(resultat.getListeRemplacements()) == 0: try: self.evaluation() except ZeroDivisionError: logging.debug("Erreur d'evaluation ZeroDivisionError") logging.debug('extractRemplacements()') self.extractRemplacements() def __decoreDep(self, intervalle, lDep): if not self.depOrdonnes: return self.__decoreDep_1(intervalle, lDep) else: return self.__decoreDep_3(intervalle, lDep) def __decoreDep_1(self, intervalle, lDep): """ Extrait de la liste générale des déplacement lDep les déplacements se situant à l'intérieur du bloc Attention !! modifie lDep Comme sur les déplacements on n'a pas d'assertions sur l'ordre, on parcourt à chaque appel de cette fonction toute la liste des déplacements.""" #if len(lDep) == 0: return [],[] if len(lDep) == 0: return [] res = [] nouvelleLDep = [] for [d,f] in lDep: #assert isinstance(d, list),str(type(d))+str(d) if intervalle[0] <= d and f <= intervalle[1] : # déplacement inlcus dans l'intervalle res.append([d,f]) else: nouvelleLDep.append([d,f]) assert len(lDep) == len(nouvelleLDep) + len(res) lDep = nouvelleLDep #return nouvelleLDep,res return res def __decoreDep_2(self, intervalle, lDep): """ Extrait de la liste générale des déplacement lDep les déplacements se situant à l'intérieur du bloc Attention !! modifie lDep et retourne res2 Ici assertion d'ordre sur les dep, recherhe d'un dep en log(n) """ #if len(lDep) == 0: return [],[] if len(lDep) == 0: return [] deb = bisect.bisect(lDep, intervalle[0]) fin = bisect.bisect(lDep, intervalle[1]) assert deb <= fin if deb == fin: # aucun déplacement n'existe dans la liste entre les 2 intervalles #return lDep,[] return [] else: res2 = lDep[deb:fin] lDep[deb:fin] = [] #lDep = lDep[:deb]+lDep[fin:] #return lDep[:deb]+lDep[fin:], lDep[deb:fin] return res2 def __decoreDep_3(self, intervalle, lDep): """ Extrait de la liste générale des déplacement lDep les déplacements se situant à l'intérieur du bloc Attention !! modifie lDep et retourne res2 Ici assertion d'ordre sur les dep, recherhe d'un dep en temps linéaire comme lDep[0] est toujours >= intervalle (parce que l'ordre est maintenu par la fonction appelante), on commence la recherche à partir de là """ if len(lDep) == 0: return [] res2 = [] i = 0 # print 'dep',lDep[0] # print 'inter',intervalle[1],intervalle[0] while len(lDep)>0 and (lDep[0][0] >= intervalle[0]) and (lDep[0][1] <= intervalle[1]): i+= 1 res2.append(lDep.pop(0)) # mofifie lDep !! return res2 def _testOrdre(self): """ Teste le bon ordre des blocs dans la liste """ posT1 = 0 # position courante dans le texte source posT2 = self.lgSource # position courante dans le texte cible prevB1 = prevB2 = (0,0,0,[]) for (B1,B2) in self.liste: if B1 is not None: # la position précédente est <= au début du bloc courant assert posT1 <= B1[1],str(posT1)+' '+str(prevB1)+' '+str(B1) posT1 = B1[2] for dep in B1[3]:# les déplacements sont bien inclus dans le bloc courant assert B1[1] <= dep[0] <= dep[1] <= B1[2] prevB1 = B1 if B2 is not None: assert posT2 <= B2[1], str(posT2)+' '+str(prevB2)+' '+str(B2) posT2 = B2[2] for dep in B2[3]: assert B2[1] <= dep[0] <= dep[1] <= B2[2] prevB2 = B2 def _testNonPerte(self, resultat): """Teste la non-perte de données lors de la création du BiblocList On teste si chaque element dans les listes de la donnée en entrée (param Resultat) est bien présent en sortie dans self.liste """ # BC T1 for (d,f) in resultat.getBlocsCommunsT1(): for (B1,B2) in self.liste: if (B1 is not None and B1[0] == 'BC' and B1[1] == d and B1[2] == f): break else: raise AssertionError("Bloc BC1 "+str((d,f))+" lost during BiblocList creation") # BC T2 for (d,f) in resultat.getBlocsCommunsT2(): for (B1,B2) in self.liste: if (B2 is not None and B2[0] == 'BC' and B2[1] == d and B2[2] == f): break else: raise AssertionError("Bloc BC2 "+str((d,f))+" lost during BiblocList creation") # Suppressions for (d,f) in resultat.getListeSuppressions(): for (B1,B2) in self.liste: if (B1 is not None and (B1[0] == 'S' or B1[0] == 'R') and B1[1] == d and B1[2] == f): break else: raise AssertionError("Bloc S "+str((d,f))+" lost during BiblocList creation") # Insertions for (d,f) in resultat.getListeInsertions(): for (B1,B2) in self.liste: if (B2 is not None and (B2[0] == 'I' or B2[0] == 'R') and B2[1] == d and B2[2] == f): break else: raise AssertionError("Bloc I "+str((d,f))+" lost during BiblocList creation") # Remplacements T1 for (d,f) in resultat.getListeRemplacementsT1(): for (B1,B2) in self.liste: if (B1 is not None and B1[0] == 'R' and B1[1] == d and B1[2] == f): break else: raise AssertionError("Bloc R1 "+str((d,f))+" lost during BiblocList creation") # Remplacements T2 for (d,f) in resultat.getListeRemplacementsT2(): for (B1,B2) in self.liste: if (B2 is not None and B2[0] == 'R' and B2[1] == d and B2[2] == f): break else: raise AssertionError("Bloc R2 "+str((d,f))+" lost during BiblocList creation") # Dep T1 for (d,f) in resultat.getListeDeplacementsT1(): for (B1,B2) in self.liste: if (B1 is not None and ((B1[0] == 'D' and B1[1] == d and B1[2] == f) or ((B1[0] == 'S' or B1[0] == 'R') and [d,f] in B1[3]) or (B1[0] == 'S' and B1[1] == d and B1[2] == f))): break else: raise AssertionError("Bloc Dep1 "+str((d,f))+" lost during BiblocList creation") # BC T2 for (d,f) in resultat.getListeDeplacementsT2(): for (B1,B2) in self.liste: if (B2 is not None and ((B2[0] == 'D' and B2[1] == d and B2[2] == f) or ((B2[0] == 'I' or B2[0] == 'R') and [d,f] in B2[3]) or (B2[0] == 'I' and B2[1] == d and B2[2] == f))): break else: raise AssertionError("Bloc Dep2 "+str((d,f))+" lost during BiblocList creation") def extractRemplacements(self): """ Recherche les S et I correspondant au critère de transformation en R et les convertit. Convertit chaque paire de bibloc (S,None) et (None,I) se suivant en un bibloc (R,R) Modifie directement self.liste plutôt que de recréer une nouvelle liste ce qui est memory expensive""" if len(self.liste) == 0: return if __debug__: old_liste = self.liste[:] tool = utile.Utile() ratio_min_remplacement = float(100)/self.planTravail.getParam().getp2() i = len(self.liste) - 2 while i >= 0: if i%1000 == 0: logging.debug("itérationR %d",i) biBloc = self.liste[i] # bibloc courant biBlocSuiv = self.liste[i+1] # bibloc suivant # on cherche un biblox S et un bibloc I qui se suivent et compatilbes # pour être transformés en (R,R) if (biBloc[0] is not None and biBloc[0][0] == 'S' and biBlocSuiv[1] is not None and biBlocSuiv[1][0] == 'I' and tool.adequation_remplacement(self.texte[biBloc[0][1]:biBloc[0][2]], self.texte[biBlocSuiv[1][1]:biBlocSuiv[1][2]], ratio_min_remplacement)): self.liste[i:i+2] = [(('R',biBloc[0][1],biBloc[0][2],biBloc[0][3]), ('R',biBlocSuiv[1][1],biBlocSuiv[1][2],biBlocSuiv[1][3]))] i -= 1 if False and __debug__: self._testOrdre() # on teste si on n'a perdu aucun elt de l'ancienne liste for (B1,B2) in old_liste: if B1 is not None: for (BN1,BN2) in self.liste: if (BN1 is not None and B1[1] == BN1[1] and B1[2] == BN1[2] and (((B1[0] == 'S' or B1[0] == 'D') and (BN1[0] == 'S' or BN1[0] == 'R' or BN1[0] == 'D') or (B1[0] == 'BC' and B1[0] == 'BC')))): break else: raise AssertionError, "elt B1 lost"+str(B1)+str(B2) if B2 is not None: for (BN1,BN2) in self.liste: if (BN2 is not None and B2[1] == BN2[1] and B2[2] == BN2[2] and (((B2[0] == 'I' or B2[0] == 'D') and (BN2[0] == 'I' or BN2[0] == 'R' or BN1[0] == 'D') or (B2[0] == 'BC' and B2[0] == 'BC')))): break else: raise AssertionError, "elt B2 lost"+str(B1)+str(B2) def extractRemplacements__(self): """ Recherche les S et I correspondant au critère de transformation en R et les convertit. Convertit chaque paire de bibloc (S,None) et (None,I) se suivant en un bibloc (R,R) """ if len(self.liste) == 0: return tool = utile.Utile() ratio_min_remplacement = float(100)/self.planTravail.getParam().getp2() nouvelleListe = [] dernierAjout = 'bloc' for i in xrange(len(self.liste)-1): biBloc = self.liste[i] # bibloc courant biBlocSuiv = self.liste[i+1] # bibloc suivant # on cherche un biblox S et un bibloc I qui se suivent et compatilbes # pour être transformés en (R,R) if (biBloc[0] is not None and biBloc[0][0] == 'S' and biBlocSuiv[1] is not None and biBlocSuiv[1][0] == 'I' and tool.adequation_remplacement(self.texte[biBloc[0][1]:biBloc[0][2]], self.texte[biBlocSuiv[1][1]:biBlocSuiv[1][2]], ratio_min_remplacement)): nouvelleListe.append((Bloc('R',biBloc[0][1],biBloc[0][2],biBloc[0][3]), Bloc('R',biBlocSuiv[1][1],biBlocSuiv[1][2],biBlocSuiv[1][3]))) dernierAjout = 'R' # ce bibloc vient d'être transformé en R elif (biBloc[1] is not None and biBloc[1][0] == 'I' and dernierAjout == 'R'): dernierAjout = 'bloc' else: nouvelleListe.append(biBloc) dernierAjout = 'bloc' if dernierAjout == 'bloc': nouvelleListe.append(self.liste[-1]) old_liste = self.liste self.liste = nouvelleListe if __debug__: self._testOrdre() # on teste si on n'a perdu aucun elt de l'ancienne liste for (B1,B2) in old_liste: if B1 is not None: for (BN1,BN2) in self.liste: if (BN1 != None and B1[1] == BN1[1] and B1[2] == BN1[2] and ((B1[0] == 'S' and (BN1[0] == 'S' or BN1[0] == 'R') or (B1[0] == 'BC' and B1[0] == 'BC')))): break else: raise AssertionError, "elt B1 lost"+str(B1)+str(B2) if B2 is not None: for (BN1,BN2) in self.liste: if (BN2 != None and B2[1] == BN2[1] and B2[2] == BN2[2] and ((B2[0] == 'I' and (BN2[0] == 'I' or BN2[0] == 'R') or (B2[0] == 'BC' and B2[0] == 'BC')))): break else: raise AssertionError, "elt B2 lost"+str(B1)+str(B2) def toResultat(self): """ Transfomre la liste de biblocs en un Resultat #############################################CHANGEMENET ICI [,] -> (,) Attention !! la liste des PAIRES de blocs déplacés n'est pas remplie """ supp = []; ins = []; rempT1 = []; rempT2 = [] BCT1 = [];BCT2 = []; depT1 = []; depT2 = [] for (B1,B2) in self.liste: # parcours toute la liste de biblocs if B1 is not None: # suivant le type de B1, l'ajoute dans la bonne liste B1_type = B1[0] if B1_type == 'S': supp.append((B1[1],B1[2])) elif B1_type == 'R': rempT1.append((B1[1],B1[2])) elif B1_type == 'D': depT1.append((B1[1],B1[2])) else: BCT1.append((B1[1],B1[2])) depT1.extend(B1[3]) if B2 is not None:# suivant le type de B2, l'ajoute dans la bonne liste B2_type = B2[0] if B2_type == 'I': ins.append((B2[1],B2[2])) elif B2_type == 'R': rempT2.append((B2[1],B2[2])) elif B2_type == 'D': depT2.append((B2[1],B2[2])) else: BCT2.append((B2[1],B2[2])) depT2.extend(B2[3]) # on extend pour former les listes des 2 fichiers pour éviter d'utliser # la concaténation de liste qui crée une nouvelle liste depT1.extend(depT2) ; del depT2 rempT1.extend(rempT2) ; del rempT2 BCT1.extend(BCT2) ; del BCT2 return Donnees.resultatAppli.Resultat(ins, supp, depT1, rempT1, self.lgSource, self.texte, BCT1, []) def evaluation(self, c1=0.5, c2=0.35, c3=0.15): """Evalue l'alignement""" assert c1+c2+c3 == 1 sep = """ !\r,\n:\t;-?"'`’()""" seq1 = self.lgSource seq2 = len(self.texte) - seq1 texte = self.texte ins = sup = remp1 = remp2 = bc1 = bc2 = dep1 = dep2 = 0.0 nb_bc1 = nb_bc2 = nb_dep1 = nb_dep2 = nb_sup = nb_ins = nb_remp1 = nb_remp2 = 0 front_bloc = front_bloc_sep = 0 lBC = [] ; lDep = [] ; lIns = [] ; lSup = [] ; lRemp = [] for (B1,B2) in self.liste: if B1 is not None: B1_type = B1[0] if B1_type == 'S': sup += B1[2]-B1[1] ; nb_sup += 1 ; front_bloc += 1 bisect.insort_right(lSup,B1[2]-B1[1]) if B1[1] == 0: front_bloc_sep += 1 elif (texte[B1[1]] in sep) or (texte[B1[1]-1] in sep): front_bloc_sep += 1 elif B1_type == 'R': remp1 += B1[2]-B1[1] ; nb_remp1 += 1 ; front_bloc += 1 bisect.insort_right(lRemp,B1[2]-B1[1]) if B1[1] == 0: front_bloc_sep += 1 elif (texte[B1[1]] in sep) or (texte[B1[1]-1] in sep): front_bloc_sep += 1 elif B1_type == 'BC': bc1 += B1[2]-B1[1] ; nb_bc1 += 1 ; front_bloc += 1 bisect.insort_right(lBC,B1[2]-B1[1]) if B1[1] == 0: front_bloc_sep += 1 elif (texte[B1[1]] in sep) or (texte[B1[1]-1] in sep): front_bloc_sep += 1 if B1_type == 'D': dep1 += B1[2]-B1[1] ; nb_dep1 += 1 ; front_bloc += 1 bisect.insort_right(lDep,B1[2]-B1[1]) if B1[1] == 0: front_bloc_sep += 1 elif (texte[B1[1]] in sep) or (texte[B1[1]-1] in sep): front_bloc_sep += 1 else: for (d,f) in B1[3]: # boucle sur les dep internes dep1 += f-d ; nb_dep1 += 1; bisect.insort_right(lDep,f-d) if B2 is not None: B2_type = B2[0] if B2_type == 'I': ins += B2[2]-B2[1] ; nb_ins += 1 ; front_bloc += 1 bisect.insort_right(lIns,B2[2]-B2[1]) if B2[1] == seq1: front_bloc_sep += 1 elif (texte[B2[1]] in sep) or (texte[B2[1]-1] in sep): front_bloc_sep += 1 elif B2_type == 'R': remp2 += B2[2]-B2[1] ; nb_remp2 += 1 ; front_bloc += 1 bisect.insort_right(lRemp,B2[2]-B2[1]) if B2[1] == seq1: front_bloc_sep += 1 elif (texte[B2[1]] in sep) or (texte[B2[1]-1] in sep): front_bloc_sep += 1 elif B2_type == 'BC': bc2 += B2[2]-B2[1] ; nb_bc2 += 1 ; front_bloc += 1 bisect.insort_right(lBC,B2[2]-B2[1]) if B2[1] == seq1: front_bloc_sep += 1 elif (texte[B2[1]] in sep) or (texte[B2[1]-1] in sep): front_bloc_sep += 1 if B2_type == 'D': dep2 += B2[2]-B2[1] ; nb_dep2 += 1 ; front_bloc += 1 bisect.insort_right(lDep,B2[2]-B2[1]) if B2[1] == seq1: front_bloc_sep += 1 elif (texte[B2[1]] in sep) or (texte[B2[1]-1] in sep): front_bloc_sep += 1 else: for (d,f) in B2[3]: # boucle sur les dep internes dep2 += f-d ; nb_dep2 += 1 ; bisect.insort_right(lDep,f-d) assert sum(lBC) == bc1+bc2 and len(lBC) == nb_bc1+nb_bc2 assert sum(lDep) == dep1+dep2 and len(lDep) == nb_dep1+nb_dep2 assert front_bloc_sep <= front_bloc #if self.planTravail.getParam().get assert bc1 == bc2,str(bc1)+' '+str(bc2) formules = ['seq1', 'seq2', '(bc1 + bc2)', '(nb_bc1 + nb_bc2)', '(0.0+bc1 + bc2) / (nb_bc1 + nb_bc2)', 'lBC[len(lBC)/2]', '(dep1 + dep2)', '(nb_dep1 + nb_dep2)', '(0.0+dep1 + dep2) / (nb_dep1 + nb_dep2)', 'lDep[len(lDep)/2]', '(bc1 + bc2) / (seq1 + seq2)', '(dep1 + dep2) / (seq1 + seq2)', '(bc1 + bc2 + dep1 + dep2)', '(nb_bc1 + nb_bc2 + nb_dep1 + nb_dep2)', '(bc1 + bc2 + dep1 + dep2) / (seq1 + seq2)', '(bc1 + bc2 - dep1 - dep2)', '(bc1 + bc2 - dep1 - dep2) / (seq1 + seq2)', '(bc1 + bc2 - sup - ins - remp1 - remp2)', '(bc1 + bc2 - sup - ins - remp1 - remp2) / (seq1 + seq2)', '(bc1 + bc2 - sup - ins - remp1 - remp2 - dep1 - dep2)', '(bc1 + bc2 - sup - ins - remp1 - remp2 - dep1 - dep2) / (seq1 + seq2)', #'(sup + ins + remp1 + remp2 + dep1 + dep2)', #'(sup + ins + remp1 + remp2 + dep1 + dep2) / (seq1 + seq2)' ] #res = '' for f in formules: try: #res += f + ' = ' + str(round(eval(f),4)) + '\n' logging.info(f + ' = ' + str(round(eval(f),4))) except Exception: #ZeroDivisionError,IndexError: continue #logging.info( ins, sup, remp1, remp2, bc1, bc2, dep1, dep2) #print res # dico pour chque type de bloc des sommes et nb de blocs dicoSommes = {} dicoSommes['inv'] = [bc1+bc2,nb_bc1,nb_bc2] dicoSommes['sup'] = [sup,nb_sup] dicoSommes['ins'] = [ins,nb_ins] dicoSommes['remp'] = [remp1+remp2,nb_remp1,nb_remp2] dicoSommes['dep'] = [dep1+dep2,nb_dep1,nb_dep2] dicoSommes['lTexte1'] = seq1 dicoSommes['lTexte2'] = seq2 dicoSommes['front'] = (front_bloc, front_bloc_sep) x = (1.0+((bc1 + bc2 - sup - ins - remp1 - remp2 - dep1 - dep2) / (seq1 +seq2)))/2.0 pri1 = (bc1 + bc2 + dep1 + dep2) / (bc1 + bc2 + dep1 + dep2 + sup + ins + remp1 + remp2) pri2 = (bc1 + bc2) / (bc1 + bc2 + dep1 + dep2) pri3 = (remp1 + remp2) / (sup + ins + remp1 + remp2) pri = (pri1 + pri2 + pri3) / 3.0 assert 0 <= pri1 <= 1, pri1 assert 0 <= pri2 <= 1, pri2 assert 0 <= pri3 <= 1, pri3 #assert 0 <= x <= 1 if nb_bc1+nb_bc2 > 0: y1 = ((0.0+bc1 + bc2) /(nb_bc1 + nb_bc2))/lBC[-1] else: y1 = 0 if nb_sup > 0: y2 = ((0.0+sup) / nb_sup) / lSup[-1] else: y2 = 0 if nb_ins > 0: y3 = ((0.0+ins) / nb_ins) / lIns[-1] else: y3 = 0 if nb_remp1+nb_remp2 > 0: y4 = ((0.0+remp1+remp2) / (nb_remp1 +nb_remp2))/ lRemp[-1] else: y4 = 0 if nb_dep1+nb_dep2 > 0: y5 = ((0.0+dep1+dep2) / (nb_dep1 + nb_dep2))/ lDep[-1] else: y5 = 0 assert 0 <= y1 <= 1, y1 assert 0 <= y2 <= 1, y2 assert 0 <= y3 <= 1, y3 assert 0 <= y4 <= 1, y4 assert 0 <= y5 <= 1, y5 #y = (0.0+(((0.0+bc1 + bc2) / max(1.0,(nb_bc1 + nb_bc2)))/lBC[-1]) + # (((0.0+sup) / max(1.0,nb_sup)) / lSup[-1]) + # (((0.0+ins) / max(1.0,nb_ins)) / lIns[-1]) + # (((0.0+remp1+remp2) / max(1.0,(nb_remp1 +nb_remp2)))/ lRemp[-1]) + # (((0.0+dep1+dep2) / max(1.0,(nb_dep1 + nb_dep2)))/ lDep[-1])) / 5.0 y = (y1 + y2 + y3 + y4 + y5) / 5.0 assert 0 <= y <= 1 ,y z0 = (0.0+bc1+bc2) / (0.0+bc1+bc2+dep1+dep2) z1 = (0.0+dep1+dep2) / (dep1+dep2+ins+sup+remp1+remp2) z2 = (0.0+remp1+remp2) / (sup+ins+remp1+remp2) z = (0.0+z1+z2)/2.0 assert 0 <= z <= 1,z sep = (0.0 + front_bloc_sep) / front_bloc assert 0 <= sep <= 1, sep sim_old = c1 * x + c2 * y + c3 *z assert 0 <= sim_old <= 1,sim_old sim = (pri + y + sep ) / 3.0 assert 0 <= sim <= 1,sim logging.info('x = ' + str(round(x,4))) logging.info('y = ' + str(round(y,4))) logging.info('z = ' + str(round(z,4))) logging.info('sim_old = ' + str(round(sim_old,4))) logging.info('pri1 = ' + str(round(pri1,4))) logging.info('pri2 = ' + str(round(pri2,4))) logging.info('pri3 = ' + str(round(pri3,4))) logging.info('pri = ' + str(round(pri,4))) logging.info('yINV = ' + str(round(y1,4))) logging.info('ySUP = ' + str(round(y2,4))) logging.info('yINS = ' + str(round(y3,4))) logging.info('yREMP = ' + str(round(y4,4))) logging.info('yDEP = ' + str(round(y5,4))) logging.info('y = ' + str(round(y,4))) logging.info('sep = ' + str(round(sep,4))) logging.info('sim = ' + str(round(sim,4))) return x,y,z,sim,dicoSommes,[y1,y2,y3,y4,y5],[z0,z1,z2], (pri1,pri2,pri3),sep def print_html(self, dossierOutput=None): """ Imprime un rapport html à partir de la liste de biblocs dossierOutput: dossier où écrire le fichier HTML """ if len(self.liste) > 10: self.print_html_streaming(dossierOutput) else: self.print_html_oneshot(dossierOutput) def print_html_streaming(self, dossierOutput=None, justPrintEntete=False): """ Imprime un rapport html en plusieurs fois pour éviter de construire toute la chaine à substituer en mémoire dossierOutput: dossier où écrire le fichier HTML """ # ouverture du template ne contenant que le début du raport template = os.path.join(Utile.constantesDonnees.REPPRIVE,"template_rapport_stream.html") ftemplate = open(template,'r') stemplate = ''.join(ftemplate.readlines()) dgm = Controleurs.DGManager.DGManager() s = Template(stemplate) # substitution des variables sres = s.safe_substitute( FILE1 = dgm.getEtatPath(self.planTravail.getAuteur(), self.planTravail.getOeuvre(),self.planTravail.getVersionSource(),self.planTravail.getEtatSource()), FILE2 = dgm.getEtatPath(self.planTravail.getAuteur(), self.planTravail.getOeuvre(),self.planTravail.getVersionCible(),self.planTravail.getEtatCible()), PARAM_PIVOTS = self.planTravail.getParam().getp1(), RATIO_REMPLACEMENTS = self.planTravail.getParam().getp2(), SEUIL_DEPLACEMENTS = self.planTravail.getParam().getp3(), PARAM_CASSE = self.__paramToON(self.planTravail.getParam().getp5()), PARAM_SEPARATEURS = self.__paramToON(self.planTravail.getParam().getp6()), PARAM_DIACRITIQUES = self.__paramToON(self.planTravail.getParam().getp7())) # écriture du rapport if dossierOutput is not None: chemin = os.path.join(dossierOutput,"rapport.html") else: chemin = os.path.join(constantes.REPMEDITE,"rapport.html") fres = open(chemin,'w') fres.write(sres) # écriture de la première partie if justPrintEntete: return fres # ecriture en streaming de la table self.__listeToHtmlTable(stream=True, fileBuffer=fres) fres.write('

') fres.close() def printTableLine(self, fBuffer): self.__listeToHtmlTable(stream=True, fileBuffer=fBuffer) def printCloseTable(self, fBuffer): fBuffer.write('

') fBuffer.close() def print_html_oneshot(self, dossierOutput=None): """ Imprime un rapport html en une seule fois dossierOutput: dossier où écrire le fichier HTML """ # ouverture du template template = os.path.join(Utile.constantesDonnees.REPPRIVE,"template_rapport.html") ftemplate = open(template,'r') stemplate = ''.join(ftemplate.readlines()) dgm = Controleurs.DGManager.DGManager() s = Template(stemplate) # substitution des variables sres = s.safe_substitute( FILE1 = dgm.getEtatPath(self.planTravail.getAuteur(), self.planTravail.getOeuvre(),self.planTravail.getVersionSource(),self.planTravail.getEtatSource()), FILE2 = dgm.getEtatPath(self.planTravail.getAuteur(), self.planTravail.getOeuvre(),self.planTravail.getVersionCible(),self.planTravail.getEtatCible()), PARAM_PIVOTS = self.planTravail.getParam().getp1(), RATIO_REMPLACEMENTS = self.planTravail.getParam().getp2(), SEUIL_DEPLACEMENTS = self.planTravail.getParam().getp3(), PARAM_CASSE = self.__paramToON(self.planTravail.getParam().getp5()), PARAM_SEPARATEURS = self.__paramToON(self.planTravail.getParam().getp6()), PARAM_DIACRITIQUES = self.__paramToON(self.planTravail.getParam().getp7()), TABLE=self.__listeToHtmlTable()) # écriture du rapport if dossierOutput is not None: chemin = os.path.join(dossierOutput,"rapport.html") else: chemin = os.path.join(constantes.REPMEDITE,"rapport.html") fres = open(chemin,'w') fres.write(sres) fres.close() def __paramToON(self,param): """ Renvoie 'Oui' ou 'Non' en fonction d'un param booléen """ if param: return "Oui" else: return "Non" def __listeToHtmlTable(self, stream=False, fileBuffer=None): """ Convertit la liste de BiBlocs en une table html Chaque Bibloc est convertit en une ligne d'une table html Si stream, on ecrit régulièrement dans fileBuffer la table courante et on la réinitialise ensuite sinon on crée une grosse chaine que l'on renvoie""" assert stream==False or (stream and fileBuffer is not None) res = [] ; i = 0 for (B1,B2) in self.liste: res.append('')# += "" # début de ligne # colonne gauche if B1 is None: res.append('') # += "" # bloc vide else: B1_type = B1[0] if B1_type == 'S': res.extend(['',self.__souligneTexte(B1),'']) # supp elif B1_type == 'R': res.extend([' ',self.__souligneTexte(B1),'']) # remp elif B1_type == 'D': res.extend(['',self.__souligneTexte(B1),'']) # dep else: res.extend(['',self.__keepMEP(self.texte[B1[1]:B1[2]]),'']) # BC # colonne droite if B2 is None: res.append('') # bloc vide else: B2_type = B2[0] if B2_type == 'I': res.extend(['',self.__souligneTexte(B2),'']) #ins elif B2_type == 'R': res.extend(['',self.__souligneTexte(B2),'']) # remp elif B2_type == 'D': res.extend(['',self.__souligneTexte(B2),'']) # dep else: res.extend(['',self.__keepMEP(self.texte[B2[1]:B2[2]]),'']) # BC res.append('\n') # fin de ligne if stream and i%50 == 0: fileBuffer.write(''.join(res)) res = [] if stream: fileBuffer.write(''.join(res)) res = [] else: return ''.join(res) def __souligneTexte(self,bloc): """ Renvoie une chaine html avec le texte souligné aux caractères déplacés """ if bloc[0] == 'D': return (''+ self.__keepMEP(self.texte[bloc[1]:bloc[2]])+'') res = "" deb = i = bloc[1] fin = bloc[2] lDep = bloc[3][:] # on copie pour ne pas modifier la liste originale # on parcours tout le bloc pour chercher les déplacements à l'intérieur de celui-ci while i < fin: # si le caractère courant est le début d'un déplacement # <= (au lieu de ==) à cause des chevauchements de déplacements du genre ('I', 5221, 5239, [(5224, 5230), (5226, 5231), (5236, 5239)]) if len(lDep) > 0 and lDep[0][0] <= i: res += ''+self.__keepMEP(self.texte[i:lDep[0][1]])+'' i = lDep[0][1] lDep.pop(0) elif len(lDep) > 0 and lDep[0][0] > i: # si on est sur du texte normal res += self.__keepMEP(self.texte[i:lDep[0][0]]) i = lDep[0][0] else: # si pas ou plus de déplacement assert len(lDep)==0 res += self.__keepMEP(self.texte[i:fin]) i = fin return res def __keepMEP(self, texte): """ Fonction chargée de conserver la mise en page du texte original Remplace les retours à la ligne par des
et les espaces par des   Le remplacement des espaces par des nbsp est très utile pour visulaiser des alignements de code source mais plus discutable pour de la langue nat. De même mais de façon moins importante pour les br.""" return texte res = "" for i in xrange(len(texte)): if texte[i] in '\r\n': res += '
' #elif texte[i] in ' ': res += ' ' else: # remplace tous les caractères spéciaux par leur code html comme   try: res += '&' + htmlentitydefs.codepoint2name[ord(texte[i])] + ';' except KeyError: res += texte[i] return res class BiBlocListWD(BiBlocList): """BiblocList avec type déplacement (D) autorisé """ def __init__(self,resultat,planTravail,depOrdonnes=True): BiBlocList.__init__(self,resultat,planTravail,depOrdonnes) try: self.evaluation() except ZeroDivisionError: logging.debug("Erreur d'evaluation ZeroDivisionError") logging.debug('extractDeplacements()') self.extractDeplacements() try: self.evaluation() except ZeroDivisionError: logging.debug("Erreur d'evaluation ZeroDivisionError") def extractDeplacements(self): """ Extraction des déplacements Teste les blocs insérés et supprimés. Si le rapport des déplacements à l'intérieur d'un bloc est supérieur au seuil Alors ce bloc est scindé en une liste de blocs (I ou S) et D Modifie directement self.liste AssertionError: 270455 ('D', 270444, 270455, []) ('D', 270450, 270455, [])""" tool = utile.Utile() ratio_seuil_lissage = float(self.planTravail.getParam().getp3()) /100 #nouvelleListe = [] i = len(self.liste) - 1 while i >= 0: if i%1000 == 0: logging.debug("itérationD %d",i) (B1,B2) = self.liste[i] if (B1 is not None and B1[0] == 'S'): # bloc S assert B2 is None supMoinsDep = tool.soustr_l_intervalles([[B1[1],B1[2]]], B1[3]) # bloc S moins les dep ratio_lissage = float(tool.longueur(supMoinsDep))/(B1[2]-B1[1]) # ratio du bloc if ratio_lissage <= ratio_seuil_lissage: self.liste[i:i+1] = self.__extractDepInsSup(supMoinsDep,B1[3],'S') elif (B2 is not None and B2[0] == 'I'):# bloc I assert B1 is None insMoinsDep = tool.soustr_l_intervalles([[B2[1],B2[2]]], B2[3]) ratio_lissage = float(tool.longueur(insMoinsDep))/(B2[2]-B2[1]) if ratio_lissage <= ratio_seuil_lissage: self.liste[i:i+1] = self.__extractDepInsSup(insMoinsDep,B2[3],'I') i -= 1 #if __debug__: # self._testOrdre() def extractDeplacements__old(self): """ Extraction des déplacements Teste les blocs insérés et supprimés. Si le rapport des déplacements à l'intérieur d'un bloc est supérieur au seuil Alors ce bloc est scindé en une liste de blocs (I ou S) et D""" tool = utile.Utile() ratio_seuil_lissage = float(self.planTravail.getParam().getp3()) /100 nouvelleListe = [] for (B1,B2) in self.liste: if (B1 is not None and B1[0] == 'S'): # bloc S assert B2 is None supMoinsDep = tool.soustr_l_intervalles([[B1[1],B1[2]]], B1[3]) # bloc S moins les dep ratio_lissage = float(tool.longueur(supMoinsDep))/(B1[2]-B1[1]) # ratio du bloc if ratio_lissage > ratio_seuil_lissage: nouvelleListe.append((B1,None)) else: nouvelleListe.extend(self.__extractDepInsSup(supMoinsDep,B1[3],'S')) elif (B2 is not None and B2[0] == 'I'):# bloc I assert B1 is None insMoinsDep = tool.soustr_l_intervalles([[B2[1],B2[2]]], B2[3]) ratio_lissage = float(tool.longueur(insMoinsDep))/(B2[2]-B2[1]) if ratio_lissage > ratio_seuil_lissage: nouvelleListe.append((None,B2)) else: nouvelleListe.extend(self.__extractDepInsSup(insMoinsDep,B2[3],'I')) else: # autres blocs: R et BC nouvelleListe.append((B1,B2)) self.liste = nouvelleListe if __debug__: self._testOrdre() def __extractDepInsSup(self,lSupOrIns,listeDep,SorI): """On scinde effectivement le blocs en une liste de blocs (S ou I) et D lSupOrIns: liste de (I ou S) listeDep: liste de D SorI: traite-on des S ou des I ? pre: isinstance(lSupOrIns,list) and isinstance(listeDep,list) (SorI == 'S' or SorI == 'I') """ nouvelleListe = [] len_listeDep = len(listeDep) prevdeb = nbDep = 0 while len(lSupOrIns) > 0 or len(listeDep) > 0: # on a ajouté tous les D, on peut ajouter le reste des (I ou S) if len(listeDep) == 0: for (deb,fin) in lSupOrIns: # pour chaque bloc (I ou S) assert prevdeb <= deb # assertion d'ordre prevdeb = deb if SorI == 'S': nouvelleListe.append((('S',deb,fin,[]),None)) # ajout effectif else: nouvelleListe.append((None,('I',deb,fin,[]))) lSupOrIns = [] # on a ajouté tous les (I ou S), on peut ajouter les reste des D elif len(lSupOrIns) == 0: for (deb,fin) in listeDep: # pour chaque bloc D assert prevdeb <= deb prevdeb = deb if SorI == 'S': nouvelleListe.append((('D',deb,fin,[]),None)) else: nouvelleListe.append((None,('D',deb,fin,[]))) nbDep += 1 listeDep = [] # si bloc courant (I ou S) <= bloc courant D alors on l'ajoute elif lSupOrIns[0][0] <= listeDep[0][0]: assert prevdeb <= lSupOrIns[0][0] prevdeb = lSupOrIns[0][0] if SorI == 'S': nouvelleListe.append((('S',lSupOrIns[0][0],lSupOrIns[0][1],[]),None)) else: nouvelleListe.append((None,('I',lSupOrIns[0][0],lSupOrIns[0][1],[]))) #lSupOrIns = lSupOrIns[1:] lSupOrIns.pop(0) else: assert prevdeb <= listeDep[0][0] prevdeb = listeDep[0][0] if SorI == 'S': nouvelleListe.append((('D',listeDep[0][0],listeDep[0][1],[]),None)) else: nouvelleListe.append((None,('D',listeDep[0][0],listeDep[0][1],[]))) listeDep.pop(0) nbDep += 1 assert len(listeDep) == len(lSupOrIns) == 0 # les 2 listes ont du etre traitées entièrement assert nbDep == len_listeDep return nouvelleListe class BiBlocListWDListe(BiBlocListWD): def __init__(self, liste, planTravail, texte, lg_texte1): self.liste = liste self.texte = texte self.lgSource = lg_texte1 self.planTravail = planTravail # sert seulement à l'affichage du rapport #self.extractInsSup() logging.debug('extractRemplacements') self.extractRemplacements() logging.debug('extractDeplacements') self.extractDeplacements() def extractInsSup(self): """ a jeter """ liste = self.liste lastFin1 = self.lgSource ; lastFin2 = len(self.texte) lastBC1 = lastBC2 = len(liste)-1 for i in xrange(len(liste)-1,-1,-1): B1,B2 = liste[i] #print B1,B2 if B2 is not None and B2[0] == 'D': accu = [] while (i-1 >= 0 and liste[i-1][1] is not None and (liste[i-1][1][0] == 'D' or liste[i-1][1][0] == 'BC')): accu.append(B2) i -= 1 B2 = liste[i][1] accu.append(B2) if i-1 < 0: start = self.lgSource else: start = liste[i-1][0][2] # fin bloc précédent dans la liste assert i <= lastBC2+1 liste[i:lastBC2+1] = [(None,('I',start,lastFin2,[(B[1],B[2]) for B in accu]))] lastFin2 = start ; lastBC2 = i elif B1 is not None and B1[0] == 'D': accu = [] while (i-1 >= 0 and liste[i-1][0] is not None and (liste[i-1][0][0] == 'D' or liste[i-1][1][0] == 'BC')): accu.append(B1) i -= 1 B1 = liste[i][0] accu.append(B1) if i-1 < 0: start = 0 else: start = liste[i-1][1][2] # fin bloc précédent dans la liste assert i <= lastBC1+1 liste[i:lastBC1+1] = [(('S',start,lastFin1,[(B[1],B[2]) for B in accu]),None)] lastFin1 = start ; lastBC1 = i else: # BC accu = [(B1,B2)] print B1,B2 assert B1[0] == 'BC' and B2[0] == 'BC', str(B1)+str(B2) if liste[lastBC1][0][1] - B1[2] > 0: accu.append((('S',B1[2],liste[lastBC1][0][1],[]),None)) if liste[lastBC2][1][1] - B2[2] > 0: accu.append((None,('I',B2[2],liste[lastBC2][1][1],[]))) liste[i:i+1] = accu lastBC1 = lastBC2 = i lastFin1 = B1[1] ; lastFin2 = B2[1] i -= 1 B1,B2 = liste[0] accu = [] if B1 is not None and B1[1] != 0: accu.append(()) #print '-----------------------------' print liste self.liste = liste