# -*- 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 #---------------------------------------------------------------------------- # Nom: MediteAppli.py #---------------------------------------------------------------------------- import sys, time,logging, gc #from time import clock, localtime, gmtime, strftime from math import * import profile,traceback,pstats,bisect import string import suffix_tree import alignement import utile from Donnees.resultatAppli import Resultat import synthetic #from caseless import dictFactory #from ft.xml.domlette import NonvalidatingReader #doc = NonvalidatingReader.parseUri("http://xmlhack.com/read.php?item=1560") #from Numeric import array, Float, ones, zeros, cumsum, searchsorted, \ # argmax, multiarray, reshape, add, allclose, floor, where, \ # product, sqrt, dot, multiply, alltrue, log, Int,equal,NewAxis,take # Seules variables globales: longueur minimale des chaines pivots (et deplacees) # ratio minimal de longueur des chaines pour valider un remplacement # et seuil du rapport de longueur des chaines pour valider un lissage global long_min_pivots global ratio_min_remplacement global ratio_seuil_lissage def transDiacritic(txt): sepTable = string.maketrans("çéèàùâêîôûäëïöüÿÇÉÈÀÙÂÊÎÔÛÄËÏÖÜ","ceeauaeiouaeiouyCEEAUAEIOUAEIOU") return txt.translate(sepTable) class ecartTextes(object): def __init__(self, chaine1, chaine2, pP1, pP2, pP3, carOuMot, caseSensitive, separatorSensivitive, diacriticSensitive, planTravail,algoAligneur=''): self.tool = utile.Utile() ## Les parametres global long_min_pivots global ratio_min_remplacement global ratio_seuil_lissage self.algoAligneur = algoAligneur # choix de l'algo, par défaut Astar long_min_pivots = pP1 ratio_min_remplacement = pP2 ratio_seuil_lissage = pP3 self.carOuMot = carOuMot self.caseSensitive = caseSensitive self.separatorSensivitive = separatorSensivitive self.diacriticSensitive = diacriticSensitive self.texte1 = chaine1 self.texte2 = chaine2 self.texte_original = self.texte1 + self.texte2 self.texte1_original = self.texte1 self.texte2_original = self.texte2 self.planTravail = planTravail # uniformisation entre espaces et espaces insécables ALT+0160 # transfo des espaces insécables en espcaces self.sepTable = string.maketrans(" "," ") self.texte1 = self.texte1.translate(self.sepTable) self.texte2 = self.texte2.translate(self.sepTable) if not self.diacriticSensitive: self.sepTable = string.maketrans("çéèàùâêîôûäëïöüÿÇÉÈÀÙÂÊÎÔÛÄËÏÖÜ","ceeauaeiouaeiouyCEEAUAEIOUAEIOU") self.texte1 = self.texte1.translate(self.sepTable) self.texte2 = self.texte2.translate(self.sepTable) if not self.caseSensitive: # si comparaison insensible à la casse, on convertit les 2 chaines en minuscule self.texte1 = self.texte1.lower() self.texte2 = self.texte2.lower() if not self.separatorSensivitive: # si insensible aux séparateurs, on convertit tous les séparateurs en point self.sepTable = string.maketrans(""" !\r,\n:\t;-?"'`’()""","................") self.texte1 = self.texte1.translate(self.sepTable) self.texte2 = self.texte2.translate(self.sepTable) # chaque clé est une position du texte original ou un séparateur a été supprimé self.dictPosSuppression={} # à chaque position du nouveau texte est associé le nb de suppression # de séparateur jusqu'à cette position self.tabNbSuppression={} self.texte1,self.texte2=self.preTraitSuppSep(self.texte1,self.texte2) #print self.dictPosSuppression #print self.tabNbSuppression #sys.stderr.write("self.tabNbSuppression = "+str(self.tabNbSuppression)+"\n") #sys.stderr.write("self.dictPosSuppression = "+str(self.dictPosSuppression)+"\n") #self.texte = self.texte1 + self.texte2 # texte intégral self.lg_texte1 = len(self.texte1) # longueur texte antérieur self.lg_texte2 = len(self.texte2) # longueur texte postérieur self.lg_texte = self.lg_texte1 + self.lg_texte2 #print "##"+self.texte1+"**" #print "##"+self.texte2+"**" sys.stdout.flush() #logging.debug('t1='+self.texte1) #logging.debug('t2='+self.texte2) # dictionnaire contenant l'ensemble des fragments répétés # ce dictionnaire est indexé par la longueur des fragments # puis par les fragments eux-mêmes. En regard, on trouve les # occurrences d'apparition de ces fragments self.blocs_texte = {} sys.stderr.flush() self.insertions = [] self.suppressions = [] self.identites = [] self.occs_texte1 = [] self.occs_texte2 = [] self.occs_deplaces = [] self.occs_remplacements = [] self.blocs_remplacements = [] self.tous_remplacements = [] #self.Dict.etat_dict() #sys.stderr.write( 'done init\n') #sys.stderr.flush() def preTraitSuppSep(self,texte1,texte2): """ Prétraitement supprimant plusieurs séparateurs se suivant et n'en laissant qu'un Prend en entrée texte1 et texte2 et les renvoie traités """ debut=0 j=0 comptSuppression=0 res=[] for texte in [texte1,texte2]: i=0 lTexte=[] while i lg_texte1 pour le mode caractère while (occs and ( -1 < self.texteMot.posCarMot(occs[0], a+a) < self.texteMot1.lengthC())): occ = occs[0] # 1e occ de la liste actuelle #n_chaine = self.texte[occ:occ+a+a] # nouvelle chaine de taille 2a # sys.stderr.write( "n_chaine = "+self.texte[occ:occ+a+a]) n_chaine = utile.chaineMot(self.texteMot.sliceC(occ, 0, occ, a+a), self.carOuMot, True) # sys.stderr.write( "n_chaine = "+n_chaine.toStr()) # n_chaine.printTab() #sys.stderr.write(" Composition: _"+n_chaine.sliceM(0,0,a,0)+"_ / _"+n_chaine.sliceM(a,0,0,n_chaine.lengthC())+"_\n") # si nouvelle chaine non présente dans dico if not self.Dict.occ_chaine(n_chaine) : #sys.stderr.write( n_chaine.toStr()+"not in dico \n") #n_chaine.printTab() # occurences de la 2e moitié de la nouvelle chaine #occs_suite = self.Dict.occs_chaine(n_chaine[a:]) occs_suite = self.Dict.occs_chaine(utile.chaineMot(n_chaine.sliceM(a,0,0,n_chaine.lengthC()),self.carOuMot, True)) if occs_suite and not self.carOuMot: # mode mot l_aux=self.tool.composition_decalee_mot(occs,occs_suite,a,self.texteMot) elif occs_suite and (len(occs_suite) > 5 or len(occs) > 7): l_aux=self.tool.composition_decalee_b(occs,occs_suite,a) else: l_aux=self.tool.composition_decalee_(occs,occs_suite,a) # l_aux contient la liste des occurences de taille 2a # enlève de occs les éléments de l_aux occs = self.tool.difference(occs[1:],l_aux) # si 2 occs de la même chaine, une dans chaque texte if self.repetition(l_aux): # ajout de la nouvelle chaine au dico self.Dict.ajout_occs(n_chaine, l_aux) else: occs = occs[1:] #self.Dict.nettoyer(a+a) for radical in self.Dict.tous_radicaux_iteration(a+a): for oc_chaine in self.Dict.toutes_occ_chaines_it(a+a, radical): #chaine = self.texte[oc_chaine:oc_chaine+a+a] chaine = utile.chaineMot(self.texteMot.sliceC(oc_chaine,0,oc_chaine,a+a),self.carOuMot,True) #for chaine in self.Dict.toutes_chaines_lg(a+a): chaine0a = utile.chaineMot(chaine.sliceC(0,0,0,a),self.carOuMot,True) occs_chaine_chaine = self.Dict.occs_chaine(chaine) if not self.repetition(self.tool.difference(self.Dict.occs_chaine(chaine0a), occs_chaine_chaine)): self.Dict.eliminer_toutes_occurrences(chaine0a) chainea2a = utile.chaineMot(chaine.sliceM(a,0,0,chaine.lengthC()),self.carOuMot,True) if not self.carOuMot and not self.repetition(self.tool.composition_decalee_mot(self.Dict.occs_chaine(chainea2a), occs_chaine_chaine, a,self.texteMot)): self.Dict.eliminer_toutes_occurrences(chainea2a) elif not self.repetition(self.tool.composition_decalee_b(self.Dict.occs_chaine(chainea2a), occs_chaine_chaine, a)): self.Dict.eliminer_toutes_occurrences(chainea2a) #self.Dict.nettoyer(a) def construction_blocs_maximaux1(self) : debut=time.clock() self.texteMot1 = utile.chaineMot(self.texte1, carOuMot, True) self.texteMot2 = utile.chaineMot(self.texte2, carOuMot, True) self.texteMot = utile.chaineMot(self.texte, carOuMot, True) #self.texteMot.printTab() self.Dict = utile.dict_chaines(260, self.texteMot, self.lg_texte1, self.carOuMot) k = 1 # initialisation de la relation d'Equivalence: E[1] -> motifs de longueur 1 # dEbut de la boucle sur k... construire la relation E pour les puissances de 2 #while 2*k <= min(self.lg_texte1, self.lg_texte2) : while 2*k <= min(self.texteMot1.lengthM(), self.texteMot2.lengthM()) : # sys.stderr.write( "Construction de la classe d'Equivalence pour 2*"+str(k)+"\n") #self.construction_equivalence_double_opt_quart(k) self.construction_equivalence_double_opt(k) #self.Dict.etat_dict() #self.eliminer_blocs_inutiles(k) #print "Nombre d'ElEments dans la classe 2*", k, ": ", len(non_nul_keys(self.E[2*k])) k = 2*k #print "fin de la construction des puissances de 2" # construction de la relation d'Equivalence pour les autres nombres #while k >= 1 : # if not self.toutes_occurrences_couvertes(k, k) : # self.ajustage(k, k) # k = k/2 #print "fin de l'ajustage" #self.ajustage_() #print "fin de l'ajustage" #self.Dict.etat_dict() # enfin, calcul des blocs maximaux... self.blocs_maximaux() # for x in self.blocs_texte: # sys.stderr.write(x+" "+str(self.blocs_texte[x])+"\n") sys.stderr.write("construction blocs max = "+str(time.clock()-debut)+"\n") sys.stderr.write("Nombre de blocs maximaux avant elimination recouvrements:"+ str(len(self.blocs_texte))+"\n") self.debut=time.clock() self.d1=self.blocs_texte # elimination des recouvrements entre blocs # sys.stderr.write("Nombre de blocs maximaux:"+str(len(self.blocs_texte))+"\n") recouv = Recouvrement(self.texte,self.blocs_texte,self.lg_texte1) self.blocs_texte = recouv.eliminer_recouvrements() # for x in self.blocs_texte: # sys.stderr.write(x+" "+str(self.blocs_texte[x])+"\n") sys.stderr.write("Nombre de blocs maximaux apres elimination recouvrements:"+ str(len(self.blocs_texte))+"\n") #self.postTraitSuppSep() # Et, pour finir, remplissage des trous par des ajouts # ou des suppressions self.completer_blocs_m() sys.stderr.write("completer_blocs_m done:"+ str(len(self.blocs_texte))+"\n") sys.stderr.flush() # for x in self.blocs_texte: # sys.stderr.write(x+" "+str(self.blocs_texte[x])+"\n") nbx=nby=0 for x in self.blocs_texte: nbx+=1 for y in self.blocs_texte[x]: nby+=1 sys.stderr.write("nbx:+"+str(nbx)+" / nby:"+str(nby)+"\n") def construction_blocs_maximaux(self) : #self.construction_blocs_maximaux1() self.construction_blocs_maximaux2() # i=0 # for x in self.d2: # if not self.d1.has_key(x): # sys.stderr.write(x+" "+str(self.d2[x])+"\n") # i+=1 # sys.stderr.write("nb= "+str(i)+"\n") def clean_bt(self): dic={} i=0 for x in self.blocs_texte: if len(x)= self.lg_texte1) def occurrence_valide(self, occ, k) : # renvoie un booléen vrai si l'occurrence est valide au rang k # c'est-à-dire si l'occurrence occ peut correspondre à un # motif de longueur k, ce qui veut dire que # (occ >= 0 et occ =< lg_texte1 - k) ou # (occ >= lg_texte1 et occ =< lg_texte1 + lg_texte2 - k) return (((occ >= 0) and (occ <= self.lg_texte1 - k)) or ((occ >= self.lg_texte1) and (occ <= self.lg_texte1 + self.lg_texte2 - k))) def completer_blocs_m(self): L = [[0, self.lg_texte1], [self.lg_texte1, self.lg_texte1 + self.lg_texte2]] LC = self.blocs_texte.keys() for chaine in LC : k = len(chaine) for occ in self.blocs_texte[chaine] : # for (occ,len_occ) in self.blocs_texte[chaine] : L = self.tool.dif_intervalles(L, [occ, occ+k]) # L = dif_intervalles(L, [occ, occ+len_occ]) #sys.stderr.write("L = "+str(L)+"\n") for inter in L : if self.blocs_texte.has_key(self.texte[inter[0]:inter[1]]): self.blocs_texte[self.texte[inter[0]:inter[1]]].append(inter[0]) # self.blocs_texte[self.texte[inter[0]:inter[1]]].append((inter[0],inter[1]-inter[0])) else: self.blocs_texte[self.texte[inter[0]:inter[1]]] = [inter[0]] # else: self.blocs_texte[self.texte[inter[0]:inter[1]]] = [(inter[0],inter[1]-inter[0])] def insertions_et_suppressions(self): """ Constructions des listes d'insertion et suppressions """ for Clef in self.blocs_texte.keys(): Occs = self.blocs_texte[Clef] # si Occs ne contient qu'une seule occurence alors elle n'est présente que dans un des 2 texte if (not self.repetition(Occs)):# or len(Clef) ratio_seuil_lissage: #ajout de l'ins complète insertions_.append(x[0]) else: # ajout de l'ins sans les déplacements insertions_ = self.tool.union(insertions_ , W) suppressions_ = [] for x in suppressions: #sys.stderr.write("SUPP2.1 : "+self.texte[x[0][0]:x[0][1]]) W = self.tool.soustr_l_intervalles([x[0]], self.occs_deplaces) ratio = float(self.tool.longueur(W))/(x[0][1]-x[0][0]) #sys.stderr.write( " / Ratio suppression: "+ str(ratio)+"\n") if ratio > ratio_seuil_lissage: suppressions_.append(x[0]) else: suppressions_ = self.tool.union(suppressions_ , W) # sys.stderr.write( " / ratio_seuil_lissage: "+ str(ratio_seuil_lissage)+"\n") # sys.stderr.write( " / suppressions_: "+ str(suppressions_)+"\n") #self.insertions = elimine_int_couverts(self.supp_liste(self.tous_remplacements,0), insertions_,self.texte) self.insertions = self.tool.elimine_int_couverts(self.tous_remplacements, insertions_) # self.suppressions = elimine_int_couverts(self.tous_remplacements, suppressions_,self.texte) self.suppressions = self.tool.elimine_int_couverts(self.supp_liste(self.tous_remplacements,1), suppressions_) # for x in self.insertions: # sys.stderr.write("INS2.3 : "+self.texte[x[0]:x[1]]+"\n") # for x in self.suppressions: # sys.stderr.write("SUPP2.3 : "+self.texte[x[0]:x[1]]+"\n") def supp_liste(self,L,texte1): res=[] for x in L: if texte1 and x[1]<=self.lg_texte1: res.append(x) elif not texte1 and x[0]>=self.lg_texte1: res.append(x) return res def reconstituer_textes(self): self.occs_texte1 = [] # occurences des blocs communs du texte 1 self.occs_texte2 = [] # occurences des blocs communs du texte 2 self.occs_deplaces = [] # pour tous les blocs appartenant aux 2 textes for x in self.identites: if x[0] < self.lg_texte1: self.occs_texte1.append(x) else: self.occs_texte2.append(x) self.statBlocs() sys.stderr.write("Debut de l'alignement\n") sys.stderr.flush() deb_al=time.clock() aligneur = alignement.AlignAstar2(self.texte) self.occs_deplaces,self.blocsCommuns = aligneur.deplacements_pond(self.occs_texte1, self.occs_texte2) sys.stderr.write("Fin de l'alignement : "+str(time.clock()-deb_al)+"\n") sys.stderr.flush() self.statLB(self.blocsCommuns,"BC") self.statLB(self.occs_deplaces,"Dep") # ajout des déplacements dans les insertions et les suppressions for x in self.occs_deplaces: if self.tool.adjacent_(x, self.insertions): #if x[0]>=self.lg_texte1: self.insertions = self.tool.ajout_intervalle(self.insertions, x) if self.tool.adjacent_(x, self.suppressions): #if x[1] 0 and blocsDepl[i][0] < self.lg_texte1): #texte1 = self.texte1[blocsDepl[i][0]:blocsDepl[i][1]] longueur = blocsDepl[i][1] - blocsDepl[i][0] for y in blocsDepl[i+1:]: if (y[0] > self.lg_texte1-1 and longueur == y[1] - y[0] and self.texte1[blocsDepl[i][0]:blocsDepl[i][1]] == self.texte2[y[0]-self.lg_texte1:y[1]-self.lg_texte1]): lDepl.append((blocsDepl[i],y)) i += 1 if filtrageDeplacements: newLDepl = [] # on ajoute les blocs en fonction de leur longueur et de leur distance for b1,b2 in lDepl: longueurBloc = b1[1] - b1[0] ajoutBloc = False # on ajoute systématiquement les grands blocs if longueurBloc > 15: ajoutBloc = True else: assert longueurBloc <= 15 positionRelativeT1 = b1[0] positionRelativeT2 = b2[0] - self.lg_texte1 assert 0 <= positionRelativeT1 < self.lg_texte1 assert 0 <= positionRelativeT2 < self.lg_texte2 # distance entre les positions des 2 blocs distanceBloc = abs(positionRelativeT1 - positionRelativeT2) #logging.debug('distanceBloc='+str(distanceBloc)) # ajout des petits blocs distants de moins d'une page if longueurBloc < 8 and distanceBloc < 3000: ajoutBloc = True # ajout des blocs moyens distants d'au plus 3 pages elif 8 <= longueurBloc <= 15 and distanceBloc < 9000: ajoutBloc = True #logging.debug((longueurBloc,b1,b2,self.texte1[b1[0]:b1[1]],self.lg_texte1,self.lg_texte2)) # si le déplacement est validé, on va l'afficher if ajoutBloc: newLDepl.append((b1,b2)) else: # sinon, il cela devient une suppression ou une insertion simple # et on l'ajoute à le liste correspondante self.suppressions = self.tool.addition_intervalle(self.suppressions, (b1[0],b1[1])) self.insertions = self.tool.addition_intervalle(self.insertions, (b2[0],b2[1])) try: # et on le supprime de la liste des déplacements k = self.occs_deplaces.index(b1) #logging.debug('k='+str(k)+' / len(o_d)='+str(len(self.occs_deplaces))) self.occs_deplaces.pop(k) except ValueError: # b1 déjà supprimé de la liste, on contiue pass #logging.debug('len(o_d)='+str(len(self.occs_deplaces))) try: #idem k = self.occs_deplaces.index(b2) self.occs_deplaces.pop(k) #logging.debug('k='+str(k)+' / len(o_d)='+str(len(self.occs_deplaces))) except ValueError: # b2 déjà supprimé de la liste, on contiue pass del lDepl lDepl = newLDepl return lDepl # Methode d'appel pour effectuer la comparaison def comparaison(self): self.construction_blocs_maximaux() # self.Dict.etat_dict() self.insertions_et_suppressions() self.reconstituer_textes() def dico_to_listes(self): """ Transformation du dico des blocs maximaux disjoints en 2 listes ordonnées, 1 par texte Les 2 listes contiennent des paires (debut de bloc, fin de bloc) """ t1 = [] t2 = [] t3 = [] for x in self.blocs_texte: t3.append((x,self.blocs_texte[x])) for y in self.blocs_texte[x]: if y < self.lg_texte1: t1.append((y,y+len(x))) else: t2.append((y,y+len(x))) # tri optimisé des listes t1.sort() t2.sort() t3.sort() t4 = [t for t in t1] t5 = [t for t in t2] t6 = [t for t in t3] return t4,t5,t6 def mode_car(self): NLC = self.m1() self.blocs_texte = NLC # for x in self.blocs_texte: # sys.stderr.write("blocs_texte["+x+"] = "+str(self.blocs_texte[x])+"\n") def rang2(self, I, S): """ Retourne la distance du bloc I dans la liste S en nombre de caractères et en nb de blocs """ ncar = 0 nbloc = 0 i=0 while i < len(S) and self.texte[I[0]:I[1]] <> self.texte[S[i][0]:S[i][1]]: ncar = ncar + S[i][1] - S[i][0] nbloc += 1 i += 1 if nbloc>1: nbloc -= 1 return ncar,nbloc def m1(self): """ Affinage du mode caractère """ t1,t2 = self.dico_to_listes() # listes de blocs des textes 1 et 2 listeBlocsCommuns=[] # liste des blocs communs aux 2 textes NLC={} # Nouvelle liste communs: nouveaux blocs communs détectés grâce au raffinage en mode caractère # indexation par la chaine et liste des positions en regard NLC1={} # idem mais seulement ceux du texte 1, indexation par la position et chaine en regard NLC2={} # idem mais seulement ceux du texte 2 LDEP={} # blocs déplacés locCumul={} # localise le début réel dans le texte des chaines concaténées cumulStr2="" #cumul des blocs à comparer précédents du texte2 cumulCompt=prevCumulCompt=0 # compteurs de cumul d1=(0,0) # bloc d1 commençant au caractère d1[0] et finissant au caractère d1[1] du texte1 # il est aligné avec le bloc d2 du texte2 f1=(0,0) # idem d1 mais aligné avec f2 d2=(self.lg_texte1,self.lg_texte1) f2=(self.lg_texte1,self.lg_texte1) bComp = False # lancer ou non une comparaison à cette itération firstAlignementDone = False # le 1er alignement entre blocs communs (BC) a été trouvé #locCumul[-1]=t2[0][1] while (t1!=[] and t2!=[]): # sys.stderr.write("t1[0] "+self.texte[t1[0][0]:t1[0][1]] +" / t2[0] "+ self.texte[t2[0][0]:t2[0][1]]+"\n") if t1==[]: # sys.stderr.write("t1 vide\n") t2=[] elif t2==[]: # sys.stderr.write("t2 vide\n") t1=[] elif self.texte[t1[0][0]:t1[0][1]] == self.texte[t2[0][0]:t2[0][1]]: # les 2 blocs courants sont identiques, on met à jour les d avec les anciens f et les f avec ces 2 nouveaux blocs # sys.stderr.write("t1[0] = t2[0]\n") if firstAlignementDone: d1=f1 f1=(t1[0][0],t1[0][1]) if firstAlignementDone: d2=f2 f2=(t2[0][0],t2[0][1]) t1=t1[1:] t2=t2[1:] bComp = True firstAlignementDone = True elif self.absent(t1[0], t2): # sys.stderr.write("t1[0] absent de t2\n") t1=t1[1:] elif self.absent(t2[0], t1): # sys.stderr.write("t2[0] absent de t1\n") t2=t2[1:] else: #on recherche le bloc le plus près dans l'autre texte et on avance dans ce texte pour retrouver ce bloc # vaut-il mieux avancer de 1 à la place de nbloc ? à tester ecart1,nbloc1 = self.rang2(t1[0],t2) #recherche du bloc t1[0] dans t2 ecart2,nbloc2 = self.rang2(t2[0],t1) # sys.stderr.write("ecart1 "+str(ecart1)+" / nbloc1 "+str(nbloc1)+" / ecart2 "+str(ecart2)+" / nbloc2 "+str(nbloc2)+"\n") if (ecart1 < ecart2 or (ecart1 == ecart2 and (t1[0][1] - t1[0][0]) > (t2[0][1] - t2[0][0]))): t2=t2[nbloc1:] else: t1=t1[nbloc2:] # sys.stderr.write("d1 "+str(d1)+" / f1 "+str(f1)+" / d2 "+str(d2)+" / f2 "+str(f2)+"\n") #si un nouvel alignement a été fait ou si on est à la fin des listes if (bComp or (t1==[] and t2==[])): listeBlocsCommuns.append((f1,f2)) #ajout du nouvel alignement à la liste des BC str1 = self.texte[d1[1]:f1[0]] # extraction des chaines à comparer entre les 2 derniers alignements str2 = self.texte[d2[1]:f2[0]] # sys.stderr.write("blocsAComparer1 = "+str1+"\n") # sys.stderr.write("blocsAComparer2 = "+str2+"\n") # sys.stderr.flush() if not(str1=="" and str2==""): appli2 = ecartTextes(str1, str2,long_min_pivots,ratio_min_remplacement, ratio_seuil_lissage, 1, self.caseSensitive, self.separatorSensivitive) # algo en mode caractère appli2.construction_blocs_maximaux() for x in appli2.blocs_texte: # pour chaque bloc résultant if x!="": # comme on permet la comparaison avec str1 ou str2 vide, des blocs vides sont retournés dans blocs_texte qui sont filtrés ici l=[] #liste des occurences du bloc x if NLC.has_key(x): #si ce bloc était déjà ajouté dans les nouveaux BC l=NLC[x] # on extrait sa liste d'occurences # sys.stderr.write("NLC[x] HAS KEY= "+x+" / l = "+str(l)+"\n") for y in appli2.blocs_texte[x]: # pour chaque nouvelle occurence # on retrouve l'occurence réelle dans le texte original if (y>=len(str1) or str1==""): # dans le texte 2 z=y+d2[1]-len(str1) NLC2[z]=x #localise à la position z tu texte 1 le bloc x else: # dans le texte 1 z=y+d1[1] NLC1[z]=x l.append(z) # ajout de cette occurence à la liste NLC[x]=l # stockage de la liste d'occurences associées au bloc x # sys.stderr.write("NLC[x] = "+str(NLC[x])+" / x = "+x+"\n") # sys.stderr.write("appli2.blocs_texte = "+str(appli2.blocs_texte)+"\n") # comparaison entre la nouvelle chaine à comparer du texte 1 et l'ensemble des # chaines nouvellement compérées précédentes concaténées du texte 2 # ceci pour détecter des nouveaux blocs communs non détectés par le mode mot # entre str1 et les chaines précédentes du texte2 # c'est à dire des déplacements if not(str1=="" and cumulStr2==""): appli3 = ecartTextes(str1, cumulStr2,long_min_pivots,ratio_min_remplacement, ratio_seuil_lissage, 1, self.caseSensitive, self.separatorSensivitive) appli3.construction_blocs_maximaux() for x in appli3.blocs_texte: if (x!="" and len(appli3.blocs_texte[x])>1): l=[] if LDEP.has_key(x): # si le bloc x a déjà été identifié comme un déplacement l=LDEP[x] # on résupère sa liste d'occurences # sys.stderr.write("LDEP[x] HAS KEY= "+x+" / l = "+str(l)+"\n") for y in appli3.blocs_texte[x]: # calcul des positions réelles if (y>=len(str1) or str1==""): z=y+locCumul[y-len(str1)][0]-len(str1)-locCumul[y-len(str1)][1] else: z=y+d1[1] if l.count(z)==0: l.append(z) LDEP[x]=l # stckage de la liste des occurences déplacées du bloc x # sys.stderr.write("LDEP[x] = "+str(LDEP[x])+" / x = "+x+"\n") # sys.stderr.write("appli3.blocs_texte = "+str(appli3.blocs_texte)+"\n") # on stocke dans locCumul pour chaque caractère de cumulStr2, la position réelle # dans le texte du bloc auquel il appartient qui est la fin du bloc aligné de gauche d2[1] while cumulCompt= self.lg_texte1: self.insertions = self.tool.ajout_intervalle(self.insertions, x) else: #print x,self.texte[x[0]:x[1]] #if self.tool.adjacent_(x, self.suppressions): self.suppressions = self.tool.ajout_intervalle(self.suppressions, x) for x in self.insertions: self.occs_texte2 = self.tool.addition_intervalle(self.occs_texte2, x) for x in self.suppressions: self.occs_texte1 = self.tool.addition_intervalle(self.occs_texte1, x) #print x,self.texte[x[0]:x[1]] # construction des occurrences de remplacements self.construire_remplacements() # construction des paires de blocs déplacés self.lDepl = self.calcPairesBlocsDeplaces(self.occs_deplaces) if not self.separatorSensivitive: self.postTraitSuppSep() def reconstituer_textes(self, coeff=None): self.occs_texte1 = [] # occurences des blocs communs du texte 1 self.occs_texte2 = [] # occurences des blocs communs du texte 2 logging.log(5,"Debut de l'alignement") deb_al=time.clock() # prendre tout le temps AStarRecur car les autres sont uniquement pour des XP #self.algoAligneur = 'HIS' if self.algoAligneur == 'Shapira' : aligneur = alignement.AlignShapiraRecur(self.lg_texte1, long_min_pivots, algoAlign=self.algoAligneur, coeff=coeff, sep=self.separatorSensivitive) elif self.algoAligneur == 'ShapiraGap' : aligneur = alignement.AlignShapiraRecurGap(self.lg_texte1, long_min_pivots, algoAlign=self.algoAligneur, coeff=coeff, sep=self.separatorSensivitive) elif self.algoAligneur == 'MOAstar': aligneur = alignement.AlignAstarRecur2(self.lg_texte1, long_min_pivots, coeff=coeff, sep=self.separatorSensivitive) else : aligneur = alignement.AlignAstarRecur(self.lg_texte1, long_min_pivots, algoAlign=self.algoAligneur, coeff=coeff, sep=self.separatorSensivitive) self.occs_deplaces,self.blocsCommuns = aligneur.run(self.texte1, self.texte2) logging.log(5,"Fin de l'alignement : %.2f s",time.clock()-deb_al) #self.statLB(self.blocsCommuns,"BC") #self.statLB(self.occs_deplaces,"Dep") # pour tous les blocs appartenant aux 2 textes #for x in self.occs_deplaces+self.blocsCommuns: # if x[0] < self.lg_texte1: self.occs_texte1.append(x) # else: self.occs_texte2.append(x) #self.extraire_ins_supp(self.occs_texte1, self.occs_texte2) #ins1 = self.insertions ; sup1 = self.suppressions #self.occs_texte1 = [] ; self.occs_texte2 = [] # on fait 2 boucles pour ne pas faire for x in L1 + L2, trop # gourmand quand les listes sont grandes for x in self.occs_deplaces: if x[0] < self.lg_texte1: self.occs_texte1 = self.tool.addition_intervalle(self.occs_texte1, x) else: self.occs_texte2 = self.tool.addition_intervalle(self.occs_texte2, x) for x in self.blocsCommuns: if x[0] < self.lg_texte1: self.occs_texte1 = self.tool.addition_intervalle(self.occs_texte1, x) else: self.occs_texte2 = self.tool.addition_intervalle(self.occs_texte2, x) self.insertions = self.tool.miroir(self.occs_texte2,self.lg_texte1,self.lg_texte) self.suppressions = self.tool.miroir(self.occs_texte1,0,self.lg_texte1) #assert len(ins1) == len(self.insertions) #assert len(sup1) == len(self.suppressions) #for x in self.occs_deplaces: #if self.tool.adjacent_(x, self.insertions): # if x[0] >= self.lg_texte1: # self.insertions = self.tool.ajout_intervalle(self.insertions, x) # else: #print x,self.texte[x[0]:x[1]] #if self.tool.adjacent_(x, self.suppressions): # self.suppressions = self.tool.ajout_intervalle(self.suppressions, x) # construction des paires de blocs déplacés #logging.debug((len(self.suppressions),self.suppressions)) self.lDepl = self.calcPairesBlocsDeplaces(self.occs_deplaces) self.insertions = self.fusionItemsAdjacents(self.insertions) self.suppressions = self.fusionItemsAdjacents(self.suppressions) if not self.separatorSensivitive: self.postTraitSuppSep() def fusionItemsAdjacents(self, liste): """Fusionne les items qui se "touchent" dans une liste cad les items dont la fin de l'un est le début de l'autre @type liste: list @param liste: liste de tuplet de blocs (debut,fin)""" i = 0 #logging.debug((len(liste),liste)) while i < len(liste)-1: #logging.debug(liste[i]) (deb,fin) = liste[i] (deb2, fin2) = liste[i+1] if ((deb == deb2 and fin == fin2) or # blocs identiques (deb2 <= deb and fin <= fin2) or # bloc i inclus dans bloc i+1 (deb <= deb2 and fin2 <= fin) or # bloc i+1 inclus dans bloc i (fin == deb2)): # blocs adjacents liste[i:i+2] = [(deb,fin2)] else: i += 1 #logging.debug((len(liste),liste)) return liste def run__(self): self.reconstituer_textes__() #sys.stderr.write("2e phase = "+str(time.clock()-self.debut)+"\n") # construction de l'instance a retourner resultat = Resultat(self.insertions, self.suppressions, self.occs_deplaces, self.tous_remplacements, self.lg_texte1, self.texte_original, self.blocsCommuns, self.lDepl) bbl = synthetic.BiBlocListWD(resultat,self.planTravail) res = bbl.toResultat() res.setPairesBlocsDeplaces(self.calcPairesBlocsDeplaces(res.getListeDeplacements())) bbl.print_html() return res def reconstituer_textes_apparies(self): """Comparaison de 2 textes déjà alignés ligne à ligne""" def addInter(src, dest1=None,dest2=None,testEquality=False): assert dest1 is not None or dest2 is not None e1 = e2 = 0 for inter in src: if isinstance(inter[0],list): # cas lDepl seulement dest1.append(([inter[0][0]+increment1,inter[0][1]+increment1], [inter[1][0]+increment2,inter[1][1]+increment2])) else: # toutes les autres listes if inter[1] <= self.lg_texte1: increment = increment1 x = (inter[0]+increment,inter[1]+increment) assert 0 <= x[0] < x[1] <= lg_texte1 dest1.append(x) e1+=1 else: increment = increment2-len(l1) x = (inter[0]+increment,inter[1]+increment) assert lg_texte1 <= x[0] < x[1] <= lg_texte,str(lg_texte1)+str(x)+str(lg_texte) dest2.append(x) e2+=1 if testEquality: assert e1 == e2 # accumulateurs des résultats intermédiaires insertions = [] ; suppressions = [] ; occs_deplaces1 = [] ; occs_deplaces2 = [] tous_remplacements1 = [] ; tous_remplacements2 = [] ; blocsCommuns1 = [] blocsCommuns2 = [] ; lDepl = [] # sauvegarde des params initiaux globaux, car ceux-ci vont être utilisés à chaque étape dans reconstituer_textes() texte1 = self.texte1 ; texte2 = self.texte2 ; lg_texte1 = self.lg_texte1 ; lg_texte2 = self.lg_texte2 sepSensitive = self.separatorSensivitive ; #texte = texte1 + texte2 ; lg_texte = len(texte) lg_texte = lg_texte1 + lg_texte2 # désactive le postTraitement dans reconstituer_textes, il ne doit etre effectué qu'à la fin de cette fonction self.separatorSensivitive = True ltexte1 = texte1.splitlines(True)# garde les \n dans chaque ligne ltexte2 = texte2.splitlines(True) #logging.debug(str(len(ltexte1))+ '/'+str(len(ltexte2))) #print texte1 assert len(ltexte1) == len(ltexte2) ,str(len(ltexte1))+'/'+str(len(texte2))# les 2 textes doivent avoir la même longueur if __debug__: t1 = t2 = 0 for l in ltexte1: t1 += len(l) for l in ltexte2: t2 += len(l) assert t1 == lg_texte1 and t2 == lg_texte-lg_texte1 increment1 = 0 ; increment2 = lg_texte1 #for i in xrange(len(ltexte1)): i = 0 while len(ltexte1) > 0: logging.debug("itération %d l à l",i) #l1 = ltexte1[i] ; l2 = ltexte2[i] l1 = ltexte1.pop(0) ; l2 = ltexte2.pop(0) #logging.debug(l1) ; logging.debug(l2) self.texte1 = l1 ; self.texte2 = l2 #self.texte = l1 + l2 self.lg_texte1 = len(l1) ; self.lg_texte2 = len(l2) self.lg_texte = self.lg_texte1 + self.lg_texte2 self.reconstituer_textes() addInter(self.insertions, dest2=insertions) addInter(self.suppressions, dest1=suppressions) addInter(self.occs_deplaces, occs_deplaces1, occs_deplaces2) addInter(self.tous_remplacements, tous_remplacements1, tous_remplacements2, True) addInter(self.blocsCommuns, blocsCommuns1, blocsCommuns2, True) addInter(lDepl, self.lDepl) increment1 += len(l1) ; increment2 += len(l2) i += 1 self.texte1 = texte1 ; self.texte2 = texte2 self.lg_texte1 = lg_texte1 ; self.lg_texte2 = lg_texte2 self.lg_texte = self.lg_texte1 + self.lg_texte2 self.separatorSensivitive = sepSensitive #; self.texte = texte self.insertions = insertions ; self.suppressions = suppressions occs_deplaces1.extend(occs_deplaces2) ; self.occs_deplaces = occs_deplaces1 tous_remplacements1.extend(tous_remplacements2) self.tous_remplacements = tous_remplacements1 blocsCommuns1.extend(blocsCommuns2) ; self.blocsCommuns = blocsCommuns1 self.lDepl = lDepl if not self.separatorSensivitive: self.postTraitSuppSep() def initialiser(self, textesApparies=False, dossierRapport=None, coeff=None): """Lancement de la comparaison entre les 2 textes si texteApparies est vrai, cela signifie que les 2 textes doivent déjà être alignés ligne à ligne, ainsi, la comparaison se fera par ligne @type textesApparies: bool @param textesApparies: les textes sont préappariés ligneà ligne @type dossierRapport: string @param dossierRapport: chemin du dossier où écrire le rapport HTML @type coeff: tuple @param coeff: tuple des 3 coefficients d'agrégation""" #gc.set_debug(gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_INSTANCES | gc.DEBUG_OBJECTS | gc.DEBUG_SAVEALL) if textesApparies: self.reconstituer_textes_apparies() #self.trace('self.reconstituer_textes_apparies()', locals()) else: self.reconstituer_textes(coeff) # construction de l'instance à retourner self.tous_remplacements = [] resultat = Resultat(self.insertions, self.suppressions, self.occs_deplaces, self.tous_remplacements, self.lg_texte1, self.texte_original, self.blocsCommuns, self.lDepl) logging.debug('Création BiBlocListWD') bbl = synthetic.BiBlocListWD(resultat,self.planTravail) #bb1 = 0 #self.trace('bbl = synthetic.BiBlocListWD(resultat,self.planTravail)', locals()) logging.debug('BiBlocListWD.toResultat()') res = bbl.toResultat() if not textesApparies: logging.debug('calcPairesBlocsDeplaces()') #res.setPairesBlocsDeplaces(self.calcPairesBlocsDeplaces2( # res.getListeDeplacementsT1(),res.getListeDeplacementsT2())) res.setPairesBlocsDeplaces(self.lDepl) logging.debug('BiBlocListWD.print_html()') bbl.print_html(dossierOutput=dossierRapport) try: bbl.evaluation() except ZeroDivisionError: logging.debug("Erreur d'evaluation ZeroDivisionError") #for obj in gc.garbage: logging.debug(obj) self.bbl = bbl #print res return res def run(self,textesApparies=False, dossierRapport=None, coeff=None): """Lance,textesApparies=False, dossierRapport=None, coeff=None si texteApparies est vrai, cela signifie que les 2 textes doivent déjà être alignés ligne à ligne, ainsi, la comparaison se fera par ligne @type textesApparies: bool @param textesApparies: les textes sont préappariés ligneà ligne @type dossierRapport: string @param dossierRapport: chemin du dossier où écrire le rapport HTML @type coeff: tuple @param coeff: tuple des 3 coefficients d'agrégation""" #gc.set_debug(gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_INSTANCES | gc.DEBUG_OBJECTS | gc.DEBUG_SAVEALL) if textesApparies: self.reconstituer_textes_apparies() #self.trace('self.reconstituer_textes_apparies()', locals()) else: self.reconstituer_textes(coeff) # construction de l'instance à retourner self.tous_remplacements = [] resultat = Resultat(self.insertions, self.suppressions, self.occs_deplaces, self.tous_remplacements, self.lg_texte1, self.texte_original, self.blocsCommuns, self.lDepl) logging.debug('Création BiBlocListWD') bbl = synthetic.BiBlocListWD(resultat,self.planTravail) #bb1 = 0 #self.trace('bbl = synthetic.BiBlocListWD(resultat,self.planTravail)', locals()) logging.debug('BiBlocListWD.toResultat()') res = bbl.toResultat() if not textesApparies: logging.debug('calcPairesBlocsDeplaces()') #res.setPairesBlocsDeplaces(self.calcPairesBlocsDeplaces2( # res.getListeDeplacementsT1(),res.getListeDeplacementsT2())) res.setPairesBlocsDeplaces(self.lDepl) logging.debug('BiBlocListWD.print_html()') bbl.print_html(dossierOutput=dossierRapport) try: bbl.evaluation() except ZeroDivisionError: logging.debug("Erreur d'evaluation ZeroDivisionError") #for obj in gc.garbage: logging.debug(obj) self.bbl = bbl #print res return res def calcPairesBlocsDeplaces2(self,blocsDepl1,blocsDepl2): """Construction de paires de blocs déplacés entre le source et le cible. On met en correspondance chaque bloc du source et le ou les blocs identiques du cible. On peut avoir un bloc source qui correspond à plusieurs cibles et vice-versa, auquel cas on aura autant de paires 2 à 2 qu'il y a de correspondances.""" lDepl = [] i=0 ; len_blocsDepl1 = len(blocsDepl1) while (i < len_blocsDepl1 and blocsDepl1[i][0] < self.lg_texte1): texte1 = self.texte1[blocsDepl1[i][0]:blocsDepl1[i][1]] longueur = blocsDepl1[i][1] - blocsDepl1[i][0] for y in blocsDepl2:#l[i+1:]: if (y[0] > self.lg_texte1-1 and longueur == y[1] - y[0] and texte1 == self.texte2[y[0]-self.lg_texte1:y[1]-self.lg_texte1]): lDepl.append((blocsDepl1[i],y)) i += 1 return lDepl def trace(self,commande,dic_locals): import hotshot,hotshot.stats,sys prof = hotshot.Profile("c:\workspace\medite\statFile") benchtime = prof.runctx(commande,globals(), dic_locals) prof.close() stats = hotshot.stats.load("c:\workspace\medite\statFile") stats.strip_dirs() stats.sort_stats('cumulative','calls','time') stats.print_stats() def xpNgram(self): def concTok(tok): if len(tok) == 1: return tok[0] elif len(tok) == 2: return tok[0]+' '+tok[1] else: return tok[0]+' '+tok[1]+' '+tok[2] texte = self.texte1 + self.texte2 dicLeftNgram = {} ; dicRightNgram = {} ; dicLeftRightNgram = {} i = 0 while i < len(self.bbl.liste)-1: b1,b2 = self.bbl.liste[i] if b1 is not None and b1[0] == 'R': b1_prec,b2_prec = self.bbl.liste[i-1] b1_suiv,b2_suiv = self.bbl.liste[i+1] if b1_prec is None or b2_prec is None or b1_suiv is None or b2_suiv is None: #,str(b1_prec)+'/'+str(b2_prec)+'/'+str(b1_suiv)+'/'+str(b2_suiv) i += 1 ; continue if b1_prec[0] != 'BC' or b2_prec[0] != 'BC' or b1_suiv[0] != 'BC' or b2_suiv[0] != 'BC': #'BC',str(b1_prec)+'/'+str(b2_prec)+'/'+str(b1_suiv)+'/'+str(b2_suiv) i += 1 ; continue tp = texte[b1_prec[1]:b1_prec[2]] ; ts = texte[b1_suiv[1]:b1_suiv[2]] tokenp = tp.split() ; tokens = ts.split() tokenp = tokenp[-3:] ; tokens = tokens[-3:] assert len(tokenp) <= 3 and len(tokens) <= 3 tokenp = concTok(tokenp) ; tokens = concTok(tokens) try: dicLeftNgram[tokenp] += 1 except KeyError: dicLeftNgram[tokenp] = 1 try: dicRightNgram[tokens] += 1 except KeyError: dicRightNgram[tokens] = 1 item = (texte[b1[1]:b1[2]],texte[b2[1]:b2[2]]) try: nb,liste = dicLeftRightNgram[tokenp,tokens] liste.append(item) dicLeftRightNgram[tokenp,tokens] = nb+1, liste except KeyError: dicLeftRightNgram[tokenp,tokens] = 1, [item] i += 1 listeLeftNgram = [] ; listeRightNgram = [] ; listeLeftRightNgram = [] #for token,nb in dicLeftNgram.iteritems(): # bisect.insort_right(listeLeftNgram,(nb,token)) #listeLeftNgram.reverse() #logging.info('listeLeftNgram:') #for x in listeLeftNgram: logging.debug(x) #logging.info('==============================') #for token,nb in dicRightNgram.iteritems(): # bisect.insort_right(listeRightNgram,(nb,token)) #listeRightNgram.reverse() #logging.info('listeRightNgram:') #for x in listeRightNgram: logging.debug(x) #logging.info('==============================') for token,(nb,item) in dicLeftRightNgram.iteritems(): bisect.insort_right(listeLeftRightNgram,(nb,token,'==>',item)) listeLeftRightNgram.reverse() logging.info('listeLeftRightNgram:') for x in listeLeftRightNgram: logging.debug(x) logging.info('==============================') class ecartTextesRecur3(ecartTextesRecur2): """ pas utilisé """ def postTraitSuppSep(self, bbl): """Modifie bbl pour reprendre les coordonnées du texte original """ tabNbSuppression = self.tabNbSuppression for i in xrange(len(bbl)-1,-1,-1): B1,B2 = bbl[i] if B1 is None: NB1 = None else: NB1 = (B1[0], B1[1] + tabNbSuppression[B1[1]], B1[2] + tabNbSuppression[B1[2]], [(d1+tabNbSuppression[d1],d2+tabNbSuppression[d2]) for (d1,d2) in B1[3]]) if B2 is None: NB2 = None else: NB2 = (B2[0], B2[1] + tabNbSuppression[B2[1]], B2[2] + tabNbSuppression[B2[2]], [(d1+tabNbSuppression[d1],d2+tabNbSuppression[d2]) for (d1,d2) in B2[3]]) bbl[i] = (NB1, NB2) self.texte1 = self.texte1_original self.texte2 = self.texte2_original #self.texte = self.texte_original self.lg_texte1 = len(self.texte1) self.lg_texte2 = len(self.texte2) def reconstituer_textes(self): logging.log(5,"Debut de l'alignement") deb_al=time.clock() aligneur = alignement.AlignAstarRecurBBL(self.lg_texte1,long_min_pivots) bbl = aligneur.run(self.texte1, self.texte2) logging.log(5,"Fin de l'alignement : %.2f s",time.clock()-deb_al) return bbl def reconstituer_textes_apparies(self, stream=False, dossierRapport=None): """Comparaison de 2 textes déjà alignés ligne à ligne""" bbl = [] # sauvegarde des params initiaux globaux, car ceux-ci vont être utilisés à chaque étape dans reconstituer_textes() texte1 = self.texte1 ; texte2 = self.texte2 ; lg_texte1 = self.lg_texte1 ; lg_texte2 = self.lg_texte2 sepSensitive = self.separatorSensivitive ; #texte = texte1 + texte2 ; lg_texte = len(texte) lg_texte = lg_texte1 + lg_texte2 # désactive le postTraitement dans reconstituer_textes, il ne doit etre effectué qu'à la fin de cette fonction self.separatorSensivitive = True ltexte1 = texte1.splitlines(True)# garde les \n dans chaque ligne ltexte2 = texte2.splitlines(True) assert len(ltexte1) == len(ltexte2) ,str(len(ltexte1))+'/'+str(len(texte2))# les 2 textes doivent avoir la même longueur if __debug__: t1 = t2 = 0 for l in ltexte1: t1 += len(l) for l in ltexte2: t2 += len(l) assert t1 == lg_texte1 and t2 == lg_texte-lg_texte1 increment1 = 0 ; increment2 = lg_texte1 i = 0 ; premier = True #gc.set_debug(gc.DEBUG_SAVEALL) while len(ltexte1) > 0: if i%100 == 0: logging.debug("itération %d l à l",i) i += 1 l1 = ltexte1.pop(0) ; l2 = ltexte2.pop(0) len_l1 = len(l1) ; len_l2 = len(l2) self.texte1 = l1 ; self.texte2 = l2 self.lg_texte1 = len_l1 ; self.lg_texte2 = len_l2 self.lg_texte = self.lg_texte1 + self.lg_texte2 bblLigne = self.reconstituer_textes() for B1,B2 in bblLigne: if B1 is None: NB1 = None else: NB1 = (B1[0], B1[1] + increment1, B1[2] + increment1, [(d1+increment1,d2+increment1) for (d1,d2) in B1[3]]) if B2 is None: NB2 = None else: NB2 = (B2[0], B2[1] + increment2-len_l1, B2[2] + increment2-len_l1, [(d1+increment2-len_l1,d2+increment2-len_l1) for (d1,d2) in B2[3]]) bbl.append((NB1, NB2)) increment1 += len_l1 ; increment2 += len_l2 if i%50 == 0 and stream: if not sepSensitive: self.postTraitSuppSep(bbl) bbl2 = synthetic.BiBlocListWDListe(bbl, self.planTravail, self.texte_original, texte1) # attention prendre les param généraux if premier: fBuffer = bbl2.print_html_streaming(dossierOutput=dossierRapport,justPrintEntete=True) premier = False bbl2.printTableLine(fBuffer) #logging.debug('1 len(gc.garbage):%d',len(gc.garbage)) #for x in gc.garbage: #logging.debug(x) # del x #for i in xrange(len(bbl)-1,-1,-1): bbl.pop() libère pas plus de mémoire del bbl ; del bbl2 ; bbl = [] #del gc.garbage[:] #logging.debug('free done') #logging.debug('2 len(gc.garbage):%d',len(gc.garbage)) #for x in gc.garbage: logging.debug(x) if stream: if not sepSensitive: self.postTraitSuppSep(bbl) bbl2 = synthetic.BiBlocListWDListe(bbl, self.planTravail, self.texte_original, texte1) # attention prendre les param généraux bbl2.printTableLine(fBuffer) bbl2.printCloseTable(fBuffer) del bbl2 ; bbl = [] self.texte1 = texte1 ; self.texte2 = texte2 self.lg_texte1 = lg_texte1 ; self.lg_texte2 = lg_texte2 self.lg_texte = self.lg_texte1 + self.lg_texte2 self.separatorSensivitive = sepSensitive #; self.texte = texte return bbl def run(self, textesApparies=False, dossierRapport=None): """Lancement de la comparaison entre les 2 textes si texteApparies est vrai, cela signifie que les 2 textes doivent déjà être alignés ligne à ligne, ainsi, la comparaison se fera par ligne """ #gc.set_debug(gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_INSTANCES | gc.DEBUG_OBJECTS | gc.DEBUG_SAVEALL) logging.debug('debut run') if textesApparies: bbl = self.reconstituer_textes_apparies() #self.trace('self.reconstituer_textes_apparies()', locals()) else: bbl = self.reconstituer_textes() if not self.separatorSensivitive: self.postTraitSuppSep(bbl) logging.debug('BiBlocListWDListe(bbl)') bbl = synthetic.BiBlocListWDListe(bbl, self.planTravail, self.texte_original, self.lg_texte1) logging.debug('BiBlocListWD.toResultat()') res = bbl.toResultat() if not textesApparies: logging.debug('calcPairesBlocsDeplaces()') res.setPairesBlocsDeplaces(self.calcPairesBlocsDeplaces2( res.getListeDeplacementsT1(),res.getListeDeplacementsT2())) logging.debug('BiBlocListWD.print_html()') bbl.print_html(dossierOutput=dossierRapport) bbl.evaluation() #for obj in gc.garbage: logging.debug(obj) return res def runStream(self, textesApparies=False, dossierRapport=None): """Lancement de la comparaison entre les 2 textes si texteApparies est vrai, cela signifie que les 2 textes doivent déjà être alignés ligne à ligne, ainsi, la comparaison se fera par ligne """ #gc.set_debug(gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_INSTANCES | gc.DEBUG_OBJECTS | gc.DEBUG_SAVEALL) logging.debug('debut run') self.bbl = self.reconstituer_textes_apparies(stream=True, dossierRapport=dossierRapport) return []