wdc
[iramuteq] / corpusNG.py
1 # -*- coding: utf-8 -*-
2 #Author: Pierre Ratinaud
3
4 import codecs
5 import os
6 import sys
7 from time import time
8 from functions import decoupercharact, ReadDicoAsDico, DoConf
9 import re
10 import sqlite3
11 import numpy
12 import itertools
13 import logging
14 from operator import itemgetter
15 from uuid import uuid4
16 from chemins import PathOut
17 from dialog import CorpusPref
18 from functions import ReadLexique, ReadDicoAsDico
19 import datetime
20
21
22 log = logging.getLogger('iramuteq.corpus')
23
24
25 def copycorpus(corpus) :
26     log.info('copy corpus')
27     copy_corpus = Corpus(corpus.parent, parametres = corpus.parametres)
28     copy_corpus.ucis = corpus.ucis
29     copy_corpus.formes = corpus.formes
30     copy_corpus.pathout = corpus.pathout
31     copy_corpus.conn_all()
32     return copy_corpus
33
34
35
36 class Corpus :
37     """Corpus class
38     list of uci
39
40     """
41     def __init__(self, parent, parametres = {}, read = False) :
42         self.parent = parent
43         self.parametres = parametres
44         self.cformes = None         
45         self.connformes = None
46         self.connuces = None
47         self.conncorpus = None
48         self.islem = False
49         self.cuces = None
50         self.ucis = []
51         self.formes = {}
52         self.flems = {}
53         self.lems = None
54         self.idformesuces = {}
55         self.iduces = None
56         self.idformes = None
57         self.uceuci = None
58         if read :
59             self.pathout = PathOut(dirout = parametres['pathout'])
60             self.read_corpus()
61
62     def add_word(self, word) :
63         if word in self.formes :
64             self.formes[word].freq += 1
65             if self.formes[word].ident in self.idformesuces :
66                 if self.ucis[-1].uces[-1].ident in self.idformesuces[self.formes[word].ident] :
67                     self.idformesuces[self.formes[word].ident][self.ucis[-1].uces[-1].ident] += 1
68                 else :
69                     self.idformesuces[self.formes[word].ident][self.ucis[-1].uces[-1].ident] = 1
70             else :
71                 self.idformesuces[self.formes[word].ident] = {self.ucis[-1].uces[-1].ident: 1}
72         else :
73             if word in self.parent.lexique :
74                 gramtype = self.parent.lexique[word][1]
75                 lem = self.parent.lexique[word][0]
76             elif word.isdigit() :
77                 gramtype = 'num'
78                 lem = word
79             else :
80                 gramtype = 'nr'
81                 lem = word
82             self.formes[word] =  Word(word, gramtype, len(self.formes), lem)
83             self.idformesuces[self.formes[word].ident] = {self.ucis[-1].uces[-1].ident : 1}
84
85     def conn_all(self): 
86         """connect corpus to db"""
87         if self.connformes is None :
88             log.info('connexion corpus')
89             self.connuces = sqlite3.connect(self.pathout['uces.db'])
90             self.cuces = self.connuces.cursor()
91             self.connformes = sqlite3.connect(self.pathout['formes.db'])
92             self.cformes = self.connformes.cursor()
93             self.conncorpus = sqlite3.connect(self.pathout['corpus.db'])
94             self.ccorpus = self.conncorpus.cursor()
95             self.cformes.execute('PRAGMA temp_store=MEMORY;')
96             self.cformes.execute('PRAGMA journal_mode=MEMORY;')
97             self.cformes.execute('PRAGMA  synchronous = OFF;')
98             self.cuces.execute('PRAGMA temp_store=MEMORY;')
99             self.cuces.execute('PRAGMA journal_mode=MEMORY;')
100             self.cuces.execute('PRAGMA  synchronous = OFF;')
101             self.ccorpus.execute('PRAGMA temp_store=MEMORY;')
102             self.ccorpus.execute('PRAGMA journal_mode=MEMORY;')
103             self.ccorpus.execute('PRAGMA  synchronous = OFF;')
104
105     def read_corpus(self) :
106         log.info('read corpus')
107         self.parametres['syscoding'] = sys.getdefaultencoding()
108         if self.conncorpus is None :
109             self.conn_all()
110         res = self.ccorpus.execute('SELECT * FROM etoiles;')
111         for row in res :
112             self.ucis.append(Uci(row[0], row[1], row[2]))
113             uces = self.conncorpus.cursor().execute('SELECT * FROM luces where uci=?;',(`self.ucis[-1].ident`,))
114             for uce in uces:
115                 self.ucis[-1].uces.append(Uce(uce[2], uce[1], uce[0]))
116         res = self.ccorpus.execute('SELECT * FROM formes;')
117         self.formes = dict([[forme[1], Word(forme[1], forme[3], forme[0], lem = forme[2], freq = forme[4])] for forme in res])
118         self.ccorpus.close()
119     
120     def getworduces(self, wordid) :
121         if isinstance(wordid, basestring) :
122             wordid = self.formes[wordid].ident
123         res = self.cformes.execute('SELECT uces FROM uces where id=? ORDER BY id;', (`wordid`,))
124         return list(itertools.chain(*[[int(val) for val in row[0].split()] if not isinstance(row[0], int) else [row[0]] for row in res]))
125
126     def getlemuces(self, lem) :
127         formesid = ', '.join([`val` for val in self.lems[lem].formes])
128         query = 'SELECT uces FROM uces where id IN (%s) ORDER BY id' % formesid
129         res = self.cformes.execute(query)
130         return list(set(list(itertools.chain(*[[int(val) for val in row[0].split()] if not isinstance(row[0], int) else [row[0]] for row in res]))))
131
132     def getlemucis(self, lem) :
133         uces = self.getlemuces(lem)
134         return list(set([self.getucefromid(val).uci for val in uces]))
135
136     def getlemuceseff(self, lem) :
137         formesid = ', '.join([`val` for val in self.lems[lem].formes])
138         query = 'SELECT uces FROM uces where id IN (%s) ORDER BY id' % formesid
139         res = self.cformes.execute(query)
140         uces = list(itertools.chain(*[[int(val) for val in row[0].split()] if not isinstance(row[0], int) else [row[0]] for row in res]))
141         query = 'SELECT eff FROM eff where id IN (%s) ORDER BY id' % formesid
142         res = self.cformes.execute(query)
143         eff = list(itertools.chain(*[[int(val) for val in row[0].split()] if not isinstance(row[0], int) else [row[0]] for row in res]))
144         lemuceeff = {}
145         for i, uce in enumerate(uces) :
146             lemuceeff[uce] = lemuceeff.get(uce, 0) + eff[i]
147         return lemuceeff    
148
149     def getlemeff(self, lem) :
150         return self.lems[lem].freq
151
152     def getlems(self) :
153         return self.lems
154
155     def getforme(self, formeid) :
156         if self.idformes is None : self.make_idformes()
157         return self.idformes[formeid]
158
159     def gettotocc(self) :
160         return sum([self.formes[forme].freq for forme in self.formes])
161
162     def getucemean(self) :
163         return float(self.gettotocc())/self.getucenb()
164
165     def getucenb(self) :
166         return self.ucis[-1].uces[-1].ident + 1
167
168     def getucinb(self) :
169         return self.ucis[-1].ident + 1
170
171     def getucisize(self) :
172         ucesize = self.getucesize()
173         return [sum(ucesize[uci.uces[0].ident:(uci.uces[-1].ident + 1)]) for uci in self.ucis]
174     
175     def getucesize(self) :
176         res = self.getalluces()
177         return [len(uce[1].split()) for uce in res]
178
179 #    def getlemseff(self) :
180 #        if self.idformes is None :
181 #            self.make_idformes()
182 #        return dict([[lem, sum([self.idformes[forme].freq for forme in self.lems[lem]])] for lem in self.lems])
183
184 #    def getlemsefftype(self) :
185 #        if self.idformes is None :
186 #            self.make_idformes()
187 #        if self.lems is None :
188 #            self.make_lems()
189 #        return dict([[lem, [sum([self.idformes[forme].freq for forme in self.lems[lem]]), '', self.idformes[self.lems[lem].keys()[0]].gram]] for lem in self.lems])
190
191     def getconcorde(self, uces) :
192         return self.cuces.execute('select * from uces where id IN (%s);' % ', '.join([`i` for i in uces])) 
193
194     def getwordconcorde(self, word) :
195         return self.getconcorde(self.getworduces(word))
196
197     def getlemconcorde(self, lem) :
198         return self.getconcorde(self.getlemuces(lem))
199
200     def getalluces(self) :
201         return self.cuces.execute('SELECT * FROM uces')
202
203     def getucesfrometoile(self, etoile) :
204         return [uce.ident for uci in self.ucis for uce in uci.uces if etoile in uci.etoiles]
205
206     def getucefromid(self, uceid) :
207         if self.iduces is None : self.make_iduces()
208         return self.iduces[uceid]
209
210     def gethapaxnb(self) :
211         return len([None for forme in self.formes if self.formes[forme].freq == 1])
212
213     def getactivesnb(self, key) :
214         return len([lem for lem in self.lems if self.lems[lem].act == key])
215 #    def make_lems(self, lem = True) :
216 #        log.info('make lems')
217 #        self.lems = {}
218 #        for forme in self.formes :
219 #            if self.formes[forme].lem in self.lems :
220 #                if self.formes[forme].ident not in self.lems[self.formes[forme].lem] :
221 #                    self.lems[self.formes[forme].lem][self.formes[forme].ident] = 0
222 #            else :
223 #                    self.lems[self.formes[forme].lem] = {self.formes[forme].ident : 0}
224
225     def getetbyuceid(self, uceid) :
226         if self.uceuci is None : self.uceuci = dict([[uce.ident,uci.ident] for uci in self.ucis for uce in uci.uces])
227         return self.ucis[self.uceuci[uceid]].etoiles
228
229     def make_lems(self, lem = True) :
230         log.info('make lems')
231         self.lems = {}
232         if lem :
233             for forme in self.formes :
234                 if self.formes[forme].lem in self.lems :
235                     if self.formes[forme].ident not in self.lems[self.formes[forme].lem].formes :
236                         self.lems[self.formes[forme].lem].add_forme(self.formes[forme])
237                 else :
238                     self.lems[self.formes[forme].lem] = Lem(self, self.formes[forme])
239         else :
240             self.lems = dict([[forme, Lem(self, self.formes[forme])] for forme in self.formes])
241                 
242     def make_idformes(self) :
243         self.idformes = dict([[self.formes[forme].ident, self.formes[forme]] for forme in self.formes])
244
245     def make_iduces(self) :
246         if self.iduces is None :
247             self.iduces = dict([[uce.ident, uce] for uci in self.ucis for uce in uci.uces])
248
249     def make_lexitable(self, mineff, etoiles) :
250         tokeep = [lem for lem in self.lems if self.lems[lem].freq > mineff]
251         etuces = [[] for et in etoiles]
252         for uci in self.ucis :
253             get = list(set(uci.etoiles).intersection(etoiles))
254             if len(get) > 1 :
255                 return '2 variables sur la meme ligne'
256             elif get != [] :
257                 etuces[etoiles.index(get[0])] += [uce.ident for uce in uci.uces]
258         etuces = [set(val) for val in etuces]
259         tab = []
260         for lem in tokeep :
261             deff = self.getlemuceseff(lem)
262             ucesk = deff.keys()
263             tab.append([lem] + [sum([deff[uce] for uce in et.intersection(ucesk)]) for et in etuces])
264         tab.insert(0, [''] + etoiles)
265         return tab
266     
267     def make_efftype_from_etoiles(self, etoiles) :
268         dtype = {}
269         etuces = [[] for et in etoiles]
270         for uci in self.ucis :
271             get = list(set(uci.etoiles).intersection(etoiles))
272             if len(get) > 1 :
273                 return '2 variables sur la meme ligne'
274             elif get != [] :
275                 etuces[etoiles.index(get[0])] += [uce.ident for uce in uci.uces]
276         etuces = [set(val) for val in etuces]
277         for lem in self.lems :
278             deff = self.getlemuceseff(lem)
279             ucesk = deff.keys()
280             gram = self.lems[lem].gram
281             if gram in dtype :
282                 dtype[gram] = [i + j for i, j in zip(dtype[gram], [sum([deff[uce] for uce in et.intersection(ucesk)]) for et in etuces])]
283             else :
284                 dtype[gram] = [sum([deff[uce] for uce in et.intersection(ucesk)]) for et in etuces]
285         tabout = [[gram] + dtype[gram] for gram in dtype]
286         tabout.insert(0, [''] + etoiles)
287         return tabout
288
289     def make_uceactsize(self, actives) :
290         res = self.getalluces()
291         ucesize = {}
292         for lem in actives: 
293             deff = self.getlemuceseff(lem)
294             for uce in deff :
295                 ucesize[uce] = ucesize.get(uce, 0) + 1
296         return ucesize
297
298     def make_uc(self, actives, lim1, lim2) :
299         uceactsize = self.make_uceactsize(actives)
300         last1 = 0
301         last2 = 0
302         uc1 = [[]]
303         uc2 = [[]]
304         lastpara = 0
305         for uce in [uce for uci in self.ucis for uce in uci.uces] :
306             if uce.para == lastpara :
307                 if last1 <= lim1 :
308                     last1 += uceactsize.get(uce.ident,0)
309                     uc1[-1].append(uce.ident)
310                 else :
311                     uc1.append([uce.ident])
312                     last1 = 0
313                 if last2 <= lim2 :
314                     last2 += uceactsize.get(uce.ident, 0)
315                     uc2[-1].append(uce.ident)
316                 else :
317                     uc2.append([uce.ident])
318                     last2 = 0
319             else :
320                 last1 = uceactsize.get(uce.ident, 0)
321                 last2 = uceactsize.get(uce.ident, 0)
322                 lastpara = uce.para
323                 uc1.append([uce.ident])
324                 uc2.append([uce.ident])
325         return uc1, uc2
326
327     def make_and_write_sparse_matrix_from_uc(self, actives, sizeuc1, sizeuc2, uc1out, uc2out, listuce1out, listuce2out) :
328         uc1, uc2 = self.make_uc(actives, sizeuc1, sizeuc2)
329         log.info('taille uc1 : %i - taille uc2 : %i' % (len(uc1), len(uc2)))
330         self.write_ucmatrix(uc1, actives, uc1out)
331         self.write_ucmatrix(uc2, actives, uc2out)
332         listuce1 = [['uce', 'uc']] + [[`uce`, `i`] for i, ucl in enumerate(uc1) for uce in ucl]
333         listuce2 = [['uce', 'uc']] + [[`uce`, `i`] for i, ucl in enumerate(uc2) for uce in ucl]
334         with open(listuce1out, 'w') as f :
335             f.write('\n'.join([';'.join(line) for line in listuce1]))
336         with open(listuce2out, 'w') as f :
337             f.write('\n'.join([';'.join(line) for line in listuce2]))
338         return len(uc1), len(uc2)
339
340     def write_ucmatrix(self, uc, actives, fileout) :
341         log.info('write uc matrix %s' % fileout)
342         uces_uc = dict([[uce, i] for i, ucl in enumerate(uc) for uce in ucl])
343         deja_la = {}
344         nbl = 0
345         with open(fileout + '~', 'w+') as f :
346             for i, lem in enumerate(actives) :
347                 for uce in self.getlemuces(lem):
348                     if (uces_uc[uce], i) not in deja_la :
349                         nbl += 1
350                         f.write(''.join([' '.join([`uces_uc[uce]+1`,`i+1`,`1`]),'\n']))
351                         deja_la[(uces_uc[uce], i)] = 0
352             f.seek(0)
353             with open(fileout, 'w') as ffin :        
354                 ffin.write("%%%%MatrixMarket matrix coordinate integer general\n%i %i %i\n" % (len(uc), len(actives), nbl))
355                 for line in f :
356                     ffin.write(line)
357         os.remove(fileout + '~')
358         del(deja_la)
359
360     def export_corpus(self, outf) :
361         #outf = 'export_corpus.txt'
362         self.make_iduces()
363         res = self.getalluces()
364         self.make_iduces()
365         actuci = ''
366         actpara = False
367         with open(outf,'w') as f :
368             for uce in res :
369                 if self.iduces[uce[0]].uci == actuci and self.iduces[uce[0]].para == actpara :
370                     f.write(uce[1].encode(self.parametres['syscoding']) + '\n')
371                 elif self.iduces[uce[0]].uci != actuci :
372                     actuci = self.iduces[uce[0]].uci
373                     if self.ucis[self.iduces[uce[0]].uci].paras == [] :
374                         actpara = self.iduces[uce[0]].para
375                         f.write('\n' + ' '.join(self.ucis[self.iduces[uce[0]].uci].etoiles).encode(self.parametres['syscoding']) + '\n' + uce[1].encode(self.parametres['syscoding']) + '\n')
376                     else :
377                         ident = 0
378                         actpara = self.iduces[uce[0]].para
379                         f.write('\n'.join([' '.join(self.ucis[self.iduces[uce[0]].uci].etoiles).encode(self.parametres['syscoding']), self.ucis[self.iduces[uce[0]].uci].paras[ident].encode(self.parametres['syscoding']), uce[1].encode(self.parametres['syscoding'])]) + '\n')
380                 elif self.iduces[uce[0]].para != actpara :
381                     actpara = self.iduces[uce[0]].para
382                     ident += 1
383                     f.write('\n'.join([self.ucis[self.iduces[uce[0]].uci].paras[ident].encode(self.parametres['syscoding']), uce[1].encode(self.parametres['syscoding'])]) + '\n')
384
385     def make_and_write_sparse_matrix_from_uces(self, actives, outfile, listuce = False) :
386         log.info('make_and_write_sparse_matrix_from_uces %s' % outfile)
387         nbl = 0
388         with open(outfile + '~', 'w+') as f :
389             for i, lem in enumerate(actives) :
390                 for uce in sorted(self.getlemuces(lem)) :
391                     nbl += 1
392                     f.write(''.join([' '.join([`uce+1`, `i+1`,`1`]),'\n']))
393             f.seek(0)
394             with open(outfile, 'w') as ffin :        
395                 ffin.write("%%%%MatrixMarket matrix coordinate integer general\n%i %i %i\n" % (self.getucenb(), len(actives), nbl))
396                 for line in f :
397                     ffin.write(line)
398         os.remove(outfile + '~')
399         if listuce :
400             with open(listuce, 'w') as f :
401                 f.write('\n'.join(['uce;uc'] + [';'.join([`i`,`i`]) for i in range(0, self.getucenb())]))
402
403     def make_and_write_sparse_matrix_from_uci(self, actives, outfile, listuci = False) :
404         log.info('make_and_write_sparse_matrix_from_ucis %s' % outfile)
405         nbl = 0
406         with open(outfile + '~', 'w+') as f :
407             for i, lem in enumerate(actives) :
408                 for uci in sorted(self.getlemucis(lem)) :
409                     nbl += 1
410                     f.write(''.join([' '.join([`uci+1`, `i+1`,`1`]),'\n']))
411             f.seek(0)
412             with open(outfile, 'w') as ffin :        
413                 ffin.write("%%%%MatrixMarket matrix coordinate integer general\n%i %i %i\n" % (self.getucinb(), len(actives), nbl))
414                 for line in f :
415                     ffin.write(line)
416         os.remove(outfile + '~')
417         if listuci :
418             with open(listuci, 'w') as f :
419                 f.write('\n'.join(['uci;uc'] + [';'.join([`i`,`i`]) for i in range(0, self.getucinb())]))
420                     
421     def make_and_write_sparse_matrix_from_classe(self, actives, uces, outfile) :
422         log.info('make_and_write_sparse_matrix_from_classe %s' % outfile)
423         nbl = 0
424         duces = dict([[uce, i] for i, uce in enumerate(uces)])
425         with open(outfile + '~', 'w+') as f :
426             for i, lem in enumerate(actives) :
427                 uces_ok = list(set(self.getlemuces(lem)).intersection(uces))
428                 for uce in uces_ok :
429                     f.write(''.join([' '.join([`duces[uce]+1`,`i+1`,`1`]),'\n']))
430             f.seek(0)
431             with open(outfile, 'w') as ffin :        
432                 ffin.write("%%%%MatrixMarket matrix coordinate integer general\n%i %i %i\n" % (self.getucenb(), len(actives), nbl))
433                 for line in f :
434                     ffin.write(line)
435         os.remove(outfile + '~')
436     
437     def make_table_with_classe(self, uces, list_act) :
438         table_uce = [[0 for val in list_act] for line in range(0,len(uces))]
439         uces = dict([[uce, i] for i, uce in enumerate(uces)])
440         for i, lem in enumerate(list_act) :
441             lemuces = list(set(self.getlemuces(lem)).intersection(uces))
442             for uce in lemuces :
443                 table_uce[uces[uce]][i] = 1
444         table_uce.insert(0, list_act)
445         return table_uce      
446
447     def parse_active(self, gramact, gramsup = None) :
448         log.info('parse actives')
449         for lem in self.lems :
450             if self.lems[lem].gram in gramact :
451                 self.lems[lem].act = 1
452             elif gramsup is not None :
453                 if self.lems[lem].gram in gramsup :
454                     self.lems[lem].act = 2
455                 else :
456                     self.lems[lem].act =  0
457             else :
458                 self.lems[lem].act = 2
459
460     def make_actives_limit(self, limit) :
461         if self.idformes is None :
462             self.make_idformes()
463         return [lem for lem in self.lems if self.getlemeff(lem) >= limit and self.lems[lem].act == 1]
464     
465     def make_actives_nb(self, nbmax, key) :
466         log.info('make_actives_nb : %i - %i' % (nbmax,key))
467         if self.idformes is None :
468             self.make_idformes()
469         allactives = [[self.lems[lem].freq, lem] for lem in self.lems if self.lems[lem].act == key and self.lems[lem].freq >= 3]
470         self.activenb = len(allactives)
471         allactives = sorted(allactives, reverse = True)
472         if len(allactives) <= nbmax :
473             log.info('nb = %i - eff min = %i ' % (len(allactives), allactives[-1][0]))
474             return [val[1] for val in allactives], allactives[-1][0]
475         else :
476             effs = [val[0] for val in allactives]
477             if effs.count(effs[nbmax - 1]) > 1 :
478                 lim = effs[nbmax - 1] + 1
479                 nok = True
480                 while nok :
481                     try :
482                         stop = effs.index(lim)
483                         nok = False
484                     except ValueError:
485                         lim -= 1
486             else :
487                 stop = nbmax - 1
488         log.info('nb actives = %i - eff min = %i ' % (stop, lim))
489         return [val[1] for val in allactives[0:stop + 1]], lim
490
491     def make_and_write_profile(self, actives, ucecl, fileout) :
492         log.info('formes/classes')
493         tab = [[lem] + [len(set(self.getlemuces(lem)).intersection(classe)) for classe in ucecl] for lem in actives]
494         tab = [[line[0]] + [`val` for val in line[1:]] for line in tab if sum(line[1:]) >= 3]
495         with open(fileout, 'w') as f :
496             f.write('\n'.join([';'.join(line) for line in tab]).encode(self.parametres['syscoding']))
497
498     def make_etoiles(self) :
499         etoiles = set([])
500         for uci in self.ucis :
501             etoiles.update(uci.etoiles[1:] + uci.paras)
502         return list(etoiles)
503
504     def make_etoiles_dict(self) :
505         etoiles = [et for uci in self.ucis for et in uci.etoiles[1:]]
506         det = {}
507         for etoile in etoiles :
508             et = etoile.split('_')
509             if et[0] in det :
510                 try :
511                     if et[1] in det[et[0]] :
512                         det[et[0]][et[1]] += 1
513                     else :
514                         det[et[0]][et[1]] = 1
515                 except IndexError :
516                     det[et[0]] += 1
517             else :
518                 try :
519                     det[et[0]] = {et[1] :1}
520                 except IndexError :
521                     det[et[0]] = 1
522         print det
523             
524
525     def make_and_write_profile_et(self, ucecl, fileout) :
526         log.info('etoiles/classes')
527         etoiles = self.make_etoiles()
528         with open(fileout, 'w') as f :
529             f.write('\n'.join([';'.join([etoile] + [`len(set(self.getucesfrometoile(etoile)).intersection(classe))` for classe in ucecl]) for etoile in etoiles]).encode(self.parametres['syscoding']))
530
531     def count_from_list(self, l, d) :
532         for val in l :
533             if val in d :
534                 d[val] += 1
535             else :
536                 d[val] = 1
537         return d
538
539     def find_segments(self, taille_segment, taille_limite) :
540         d = {}
541         for uce in self.getalluces() :
542             uce = uce[1].split()
543             d = self.count_from_list([' '.join(uce[i:i+taille_segment]) for i in range(len(uce)-(taille_segment - 1))], d)
544         l = [[d[val], val] for val in d if d[val] >= 3]
545         del(d)
546         l.sort()
547         if len(l) > taille_limite :
548             l = l[-taille_limite:]
549         return l
550          
551     def make_ucecl_from_R(self, filein) :
552         with open(filein, 'rU') as f :
553             c = f.readlines()
554         c.pop(0)
555         self.lc = []
556         for line in c :
557             line = line.replace('\n', '').replace('"', '').split(';')
558             self.lc.append([int(line[0]) - 1, int(line[1])])
559         classesl = [val[1] for val in self.lc]
560         clnb = max(classesl)
561         self.lc = sorted(self.lc, key=itemgetter(1))
562         self.lc = [[uce[0] for uce in self.lc if uce[1] == i] for i in range(clnb+1)]
563         self.lc0 = self.lc.pop(0)
564         #return ucecl
565
566     def gethapaxbyet(self, etoiles) :
567         hapaxuces = [self.getlemuces(forme)[0] for forme in self.lems if self.lems[forme].freq == 1]
568         hucesdict = {}
569         for uce in hapaxuces :
570             if uce in hucesdict :
571                 hucesdict[uce] += 1
572             else :
573                 hucesdict[uce] = 1
574         etuces = [[] for et in etoiles]
575         for uci in self.ucis :
576             get = list(set(uci.etoiles).intersection(etoiles))
577             if len(get) > 1 :
578                 return '2 variables sur la meme ligne'
579             elif get != [] :
580                 etuces[etoiles.index(get[0])] += [uce.ident for uce in uci.uces]
581         etuces = [set(val) for val in etuces]
582         return [sum([hucesdict[uce] for uce in list(etuce.intersection(hapaxuces))]) for etuce in etuces]
583
584     def gethapaxuces(self) :
585         hapaxuces = [self.getlemuces(forme)[0] for forme in self.lems if self.lems[forme].freq == 1]
586         hapax = [forme for forme in self.lems if self.lems[forme].freq == 1]
587         hucesdict = {}
588         for i,uce in enumerate(hapaxuces) :
589             if uce in hucesdict :
590                 hucesdict[uce][0] += 1
591                 hucesdict[uce][1].append(hapax[i])
592             else :
593                 hucesdict[uce] = [1,[hapax[i]]]
594         huces = {}
595         for uce in hucesdict :
596             if hucesdict[uce][0] in huces :
597                 huces[hucesdict[uce][0]].append(uce)
598             else :
599                 huces[hucesdict[uce][0]] = [uce]
600         huces = zip(huces, huces.values())
601         huces.sort(reverse=True)
602         txt = """
603         <html><body>
604         """
605         for nb in huces[0:4] :
606             txt += "<p><h2>%i hapax par uce</h2><p>\n" % nb[0]
607             for uce in nb[1] :
608                 res = self.getconcorde([uce])
609                 for row in res :
610                     ucetxt = ' ' + row[1] + ' '
611                     uceid = row[0]
612                 for hap in hucesdict[uce][1] :
613                     laforme = self.getforme([forme for forme in self.lems[hap].formes][0]).forme
614                     ucetxt = ucetxt.replace(' '+laforme+' ', ' <font color=red>'+laforme+'</font> ')
615                 txt += '<p><b>' + ' '.join(self.getetbyuceid(uceid)) + '</b></p>'
616                 txt += '<p>'+ucetxt+'</p>\n'
617         txt += """
618         </body></html>
619         """
620         with open('/tmp/testhapxuce.html','w') as f :
621             f.write(txt)
622
623
624 class MakeUciStat :
625     def __init__(self, corpus) :
626         ucinb = corpus.getucinb()
627         ucisize = corpus.getucisize()
628         ucimean = float(sum(ucisize))/float(ucinb)
629         detoile = corpus.make_etoiles_dict()
630         
631
632 class Uci :
633     def __init__(self, iduci, line, paraset = None) :
634         self.ident = iduci
635         self.etoiles = line.split()
636         self.uces = []
637         if paraset is not None :
638             self.paras = paraset.split()
639         else :
640             self.paras = []
641
642 class Uce :
643     def __init__(self, iduce, idpara, iduci) :
644         self.ident = iduce
645         self.para = idpara
646         self.uci = iduci
647
648 class Word :
649     def __init__(self, word, gramtype, idword, lem = None, freq = None) :
650         self.forme = word
651         self.lem = lem
652         self.gram = gramtype
653         self.ident = idword
654         self.act = 1
655         if freq is not None :
656             self.freq = freq
657         else :
658             self.freq = 1
659
660 class Lem :
661     def __init__(self, parent, forme) :
662         self.formes = {forme.ident : forme.freq}
663         self.gram = forme.gram
664         self.freq = forme.freq
665         self.act = forme.act
666
667     def add_forme(self, forme) :
668         self.formes[forme.ident] = forme.freq
669         self.freq += forme.freq
670
671 def decouperlist(chaine, longueur, longueurOptimale) :
672     """
673         on part du dernier caractère, et on recule jusqu'au début de la chaîne.
674         Si on trouve un '$', c'est fini.
675         Sinon, on cherche le meilleur candidat. C'est-à-dire le rapport poids/distance le plus important.
676     """
677     separateurs = [[u'.', 6.0], [u'?', 6.0], [u'!', 6.0], [u'£', 6.0], [u':', 5.0], [u';', 4.0], [u',', 1.0], [u' ', 0.01]]
678     dsep = dict([[val[0],val[1]] for val in separateurs])
679     trouve = False                 # si on a trouvé un bon séparateur
680     iDecoupe = 0                # indice du caractere ou il faut decouper
681     
682     longueur = min(longueur, len(chaine) - 1)
683     chaineTravail = chaine[:longueur + 1]
684     nbCar = longueur
685     meilleur = ['', 0, 0]        # type, poids et position du meilleur separateur
686     
687     try :
688         indice = chaineTravail.index(u'$')
689         trouve = True
690         iDecoupe = indice - 1
691     except ValueError :
692         pass
693     if not trouve:
694         while nbCar >= 0:
695             caractere = chaineTravail[nbCar]
696             distance = abs(longueurOptimale - nbCar) + 1
697             meilleureDistance = abs(longueurOptimale - meilleur[2]) + 1
698             if caractere in dsep :
699                 if (float(dsep[caractere]) / distance) > (float(meilleur[1]) / meilleureDistance) :
700                     meilleur[0] = caractere
701                     meilleur[1] = dsep[caractere]
702                     meilleur[2] = nbCar
703                     trouve = True
704                     iDecoupe = nbCar
705             else :
706                 if (float(dsep[' ']) / distance) > (float(meilleur[1]) / meilleureDistance) :
707                     meilleur[0] = ' '
708                     meilleur[1] = dsep[' ']
709                     meilleur[2] = nbCar
710                     trouve = True
711                     iDecoupe = nbCar
712             nbCar = nbCar - 1
713     # si on a trouvé
714     if trouve:
715         #if meilleur[0] != ' ' :
716         #    fin = chaine[iDecoupe + 1:]
717         #    retour = chaineTravail[:iDecoupe]
718         #else :
719         fin = chaine[iDecoupe + 1:]
720         retour = chaineTravail[:iDecoupe + 1]
721         return len(retour) > 0, retour, fin
722     # si on a rien trouvé
723     return False, chaine, ''
724
725 def testetoile(line) :
726     return line.startswith(u'****')
727
728 def testint(line) :
729     return line[0:4].isdigit() and u'*' in line
730
731 def prep_txtlist(txt) :
732     return txt.split() + [u'$']
733
734 def prep_txtcharact(txt) :
735     return txt + u'$'
736
737 class BuildCorpus :
738     """
739     Class for building a corpus
740     """
741     def __init__(self, infile, parametres_corpus, lexique = None, expressions = None, dlg = None) :
742         log.info('begin building corpus...')
743         self.lexique = lexique
744         self.expressions = expressions
745         self.dlg = dlg
746         self.corpus = Corpus(self, parametres_corpus)
747         self.infile = infile
748         self.last = 0
749         self.lim = parametres_corpus.get('lim', 1000000)
750         self.encoding = parametres_corpus['encoding']
751         self.corpus.pathout = PathOut(filename = parametres_corpus['originalpath'], dirout = parametres_corpus['pathout'])
752         self.corpus.pathout.createdir(parametres_corpus['pathout'])
753         self.corpus.parametres['uuid'] = str(uuid4())
754         self.corpus.parametres['corpus_name'] = os.path.split(self.corpus.parametres['pathout'])[1]
755         self.corpus.parametres['type'] = 'corpus'
756         if self.corpus.parametres['keep_ponct'] :
757             self.ponctuation_espace = [' ', '']
758         else :
759             self.ponctuation_espace =  [' ','.', u'£', ';', '?', '!', ',', ':','']
760         self.cleans = []
761         self.tolist = self.corpus.parametres.get('tolist', 0)
762         self.buildcleans()
763         self.prep_makeuce()
764         #create database
765         self.connect()
766         self.dobuild()
767
768     def prep_makeuce(self) :
769         method = self.corpus.parametres.get('ucemethod', 0)
770         if method == 1 :
771             self.decouper = decouperlist
772             self.prep_txt = prep_txtlist
773             self.ucesize = self.corpus.parametres.get('ucesize', 40)
774         elif method == 0 :
775             self.decouper = decoupercharact
776             self.prep_txt = prep_txtcharact
777             self.ucesize = self.corpus.parametres.get('ucesize', 240)
778         log.info('method uce : %s' % method)
779
780     def dobuild(self) :    
781         t1 = time()
782         self.read_corpus(self.infile)
783         self.indexdb()
784         self.corpus.parametres['ira'] = self.corpus.pathout['Corpus.cira']
785         self.time = time() - t1
786         self.dofinish()
787         DoConf().makeoptions(['corpus'],[self.corpus.parametres], self.corpus.pathout['Corpus.cira'])
788         log.info('time : %f' % (time() - t1))
789
790     def connect(self) :
791         self.conn_f = sqlite3.connect(self.corpus.pathout['formes.db'])
792         self.cf = self.conn_f.cursor()
793         self.cf.execute('CREATE TABLE IF NOT EXISTS uces (id INTEGER, uces TEXT);')
794         self.cf.execute('CREATE TABLE IF NOT EXISTS eff (id INTEGER, eff TEXT);')
795         self.conn_f.commit()
796         self.cf = self.conn_f.cursor()
797         self.cf.execute('PRAGMA temp_store=MEMORY;')
798         self.cf.execute('PRAGMA journal_mode=MEMORY;')
799         self.cf.execute('PRAGMA  synchronous = OFF;')
800         self.cf.execute('begin')
801         self.conn = sqlite3.connect(self.corpus.pathout['uces.db'])
802         self.c = self.conn.cursor()
803         self.c.execute('CREATE TABLE IF NOT EXISTS uces (id INTEGER, uces TEXT);')
804         self.conn.commit()
805         self.c = self.conn.cursor()
806         self.c.execute('PRAGMA temp_store=MEMORY;')
807         self.c.execute('PRAGMA journal_mode=MEMORY;')
808         self.c.execute('PRAGMA  synchronous = OFF;')
809         self.c.execute('begin')
810
811     def indexdb(self) :
812         #commit index and close db
813         self.conn.commit()
814         self.conn_f.commit()
815         self.cf.execute('CREATE INDEX iduces ON uces (id);')
816         self.cf.execute('CREATE INDEX ideff ON eff (id);')
817         self.c.close()
818         self.cf.close()
819         #backup corpora
820         self.conn_corpus = sqlite3.connect(self.corpus.pathout['corpus.db'])
821         self.ccorpus = self.conn_corpus.cursor()
822         self.ccorpus.execute('CREATE TABLE IF NOT EXISTS etoiles (uci INTEGER, et TEXT, paras TEXT);')
823         self.ccorpus.execute('CREATE TABLE IF NOT EXISTS luces (uci INTEGER, para INTEGER, uce INTEGER);')
824         self.ccorpus.execute('CREATE TABLE IF NOT EXISTS formes (ident INTEGER, forme TEXT, lem TEXT, gram TEXT, freq INTEGER);')
825         self.conn_corpus.commit()
826         self.ccorpus = self.conn_corpus.cursor()
827         self.ccorpus.execute('PRAGMA temp_store=MEMORY;')
828         self.ccorpus.execute('PRAGMA journal_mode=MEMORY;')
829         self.ccorpus.execute('PRAGMA  synchronous = OFF;')
830         self.ccorpus.execute('begin')
831         self.backup_corpus()
832         self.ccorpus.execute('CREATE INDEX iduci ON luces (uci);')
833         self.conn_corpus.commit()
834         self.conn_corpus.close()
835         #self.corpus.parametres['corpus_ira'] = self.corpus.pathout['corpus.cira']
836
837     def buildcleans(self) :
838         if self.corpus.parametres.get('lower', 1) :
839             self.cleans.append(self.dolower)
840         if self.corpus.parametres.get('firstclean', 1) :
841             self.cleans.append(self.firstclean)
842         self.rule = self.corpus.parametres.get('keep_caract', u"^a-zA-Z0-9àÀâÂäÄáÁéÉèÈêÊëËìÌîÎïÏòÒôÔöÖùÙûÛüÜçÇßœŒ’ñ.:,;!?*'_-")
843         self.cleans.append(self.docharact)
844         if self.corpus.parametres.get('expressions', 1) :
845             self.cleans.append(self.make_expression)
846         if self.corpus.parametres.get('apos', 1) :
847             self.cleans.append(self.doapos)
848         if self.corpus.parametres.get('tiret', 1):
849             self.cleans.append(self.dotiret)
850
851     def make_expression(self,txt) :
852          for expression in self.expressions:
853             if expression in txt :
854                 txt = txt.replace(expression, self.expressions[expression][0])
855          return txt
856     
857     def dolower(self, txt) :
858         return txt.lower()
859
860     def docharact(self, txt) :
861         #rule = u"^a-zA-Z0-9àÀâÂäÄáÁéÉèÈêÊëËìÌîÎïÏòÒôÔöÖùÙûÛüÜçÇßœŒ’ñ.:,;!?*'_-"
862         list_keep = u"[" + self.rule + "]+"
863         return re.sub(list_keep, ' ', txt)
864     
865     def doapos(self, txt) :
866         return txt.replace(u'\'', u' ')
867
868     def dotiret(self, txt) :
869         return txt.replace(u'-', u' ')
870
871     def firstclean(self, txt) :
872         txt = txt.replace(u'’',"'")
873         txt = txt.replace(u'œ', u'oe')
874         return txt.replace('...',u' £ ').replace('?',' ? ').replace('.',' . ').replace('!', ' ! ').replace(',',' , ').replace(';', ' ; ').replace(':',' : ')
875
876     def make_cleans(self, txt) :
877         for clean in self.cleans :
878             txt = clean(txt)
879         return txt
880
881     def backup_uce(self) :
882         if self.corpus.idformesuces != {} :
883             log.info('backup %i' % len(self.corpus.idformesuces))
884             touce = [(`forme`, ' '.join([`val` for val in  self.corpus.idformesuces[forme].keys()])) for forme in self.corpus.idformesuces]
885             toeff = [(`forme`, ' '.join([`val` for val in  self.corpus.idformesuces[forme].values()])) for forme in self.corpus.idformesuces]
886             self.cf.executemany('INSERT INTO uces VALUES (?,?);', touce)
887             self.cf.executemany('INSERT INTO eff VALUES (?,?);', toeff)
888         self.corpus.idformesuces = {}        
889         self.count = 1
890
891     def backup_corpus(self) :
892         log.info('start backup corpus')
893         t = time()
894         for uci in self.corpus.ucis :
895             self.ccorpus.execute('INSERT INTO etoiles VALUES (?,?,?);' ,(uci.ident,' '.join(uci.etoiles), ' '.join(uci.paras,)))
896             for uce in uci.uces : 
897                 self.ccorpus.execute('INSERT INTO luces VALUES (?,?,?);',(`uci.ident`,`uce.para`,`uce.ident`,))
898         for forme in self.corpus.formes :
899             self.ccorpus.execute('INSERT INTO formes VALUES (?,?,?,?,?);', (`self.corpus.formes[forme].ident`, forme, self.corpus.formes[forme].lem, self.corpus.formes[forme].gram, `self.corpus.formes[forme].freq`,))
900         log.info('%f' % (time() - t))
901
902     def dofinish(self) :
903         self.corpus.parametres['date'] = datetime.datetime.now().ctime()
904         minutes, seconds = divmod(self.time, 60)
905         hours, minutes = divmod(minutes, 60)
906         self.corpus.parametres['time'] = '%.0fh %.0fm %.0fs' % (hours, minutes, seconds)
907         self.corpus.parametres['ucinb'] = self.corpus.getucinb()
908         self.corpus.parametres['ucenb'] = self.corpus.getucenb()
909         self.corpus.parametres['occurrences'] = self.corpus.gettotocc()
910         self.corpus.parametres['formesnb'] = len(self.corpus.formes)
911         hapaxnb = self.corpus.gethapaxnb()
912         pourhapaxf = (float(hapaxnb) / len(self.corpus.formes)) * 100
913         pourhapaxocc = (float(hapaxnb) / self.corpus.parametres['occurrences']) * 100
914         self.corpus.parametres['hapax'] = '%i - %.2f %% des formes - %.2f %% des occurrences' % (hapaxnb, pourhapaxf, pourhapaxocc)
915
916
917 class BuildFromAlceste(BuildCorpus) :
918     #def __init___(self, infile, parametres_corpus) :
919     #    BuildCorpus.__init__(self, infile, parametres_corpus)
920
921
922     def read_corpus(self, infile) :
923         self.limitshow = 0
924         self.count = 1
925         if self.corpus.parametres['ucimark'] == 0 :
926             self.testuci = testetoile
927         elif  self.corpus.parametres['ucimark'] == 1 :
928             self.testuci = testint
929         txt = []
930         iduci = -1
931         idpara = -1
932         iduce = -1
933         with codecs.open(infile, 'rU', self.encoding) as f :
934             for line in f :
935                 if self.testuci(line) :
936                     iduci += 1
937                     if txt != [] :
938                         iduce, idpara = self.treattxt(txt, iduce, idpara, iduci - 1)
939                         txt = []
940                         self.corpus.ucis.append(Uci(iduci, line))
941                     else :
942                         self.corpus.ucis.append(Uci(iduci, line))
943                 elif line.startswith(u'-*') :
944                     if txt != [] :
945                         iduce, idpara = self.treattxt(txt, iduce, idpara, iduci)
946                         txt = []
947                     idpara += 1
948                     self.corpus.ucis[-1].paras.append(line.split()[0])
949                 elif line.strip() != '' and iduci != -1 :
950                     txt.append(line)
951         if txt != [] :
952             iduce, idpara = self.treattxt(txt, iduce, idpara, iduci)
953             del(txt)
954         self.backup_uce()
955
956     def treattxt(self, txt, iduce, idpara, iduci) :
957         if self.corpus.parametres.get('ucemethod', 0) == 2 and self.corpus.parametres['douce']:
958             txt = 'laphrasepoursplitter'.join(txt)
959             txt = self.make_cleans(txt)
960             txt = ' '.join([val for val in txt.split() if val not in self.ponctuation_espace])
961             ucetxt = txt.split('laphrasepoursplitter')
962         else :
963             txt = ' '.join(txt)
964             txt = self.make_cleans(txt)
965             ucetxt = self.make_uces(txt, self.corpus.parametres['douce'])
966         if self.corpus.ucis[-1].paras == [] :
967             idpara += 1
968         for uce in ucetxt :
969             iduce += 1
970             self.corpus.ucis[-1].uces.append(Uce(iduce, idpara, iduci))
971             self.c.execute('INSERT INTO uces VALUES(?,?);', (`iduce`,uce))
972             if not self.tolist :
973                 uce = uce.split()
974             else :
975                 uce = list(uce)
976             for word in uce :
977                 self.last += 1
978                 self.corpus.add_word(word)
979         if self.dlg is not None :
980             if self.limitshow > self.count :
981                 self.dlg.Pulse('uci: %i - uce : %i' % (iduci + 1, iduce +1))
982                 self.count += 1
983                 self.limitshow = 0
984             else :
985                 self.limitshow = self.last / 100000
986         log.debug(`iduci`, `idpara`, `iduce`)
987         if self.last > self.lim :
988             self.backup_uce()
989             self.last = 0
990         return iduce, idpara
991
992     def make_uces(self, txt, douce = True, keep_ponct = False) :
993         txt = ' '.join(txt.split())
994         if douce :
995             out = []
996             reste, texte_uce, suite = self.decouper(self.prep_txt(txt), self.ucesize + 15, self.ucesize)
997 #            print 'reste'
998 #            print reste
999 #            print 'texte_uce'
1000 #            print texte_uce
1001 #            print 'suite'
1002 #            print suite
1003             while reste :
1004                 uce = ' '.join([val for val in texte_uce if val not in self.ponctuation_espace])
1005                 if uce != '' :
1006                     out.append(uce)
1007                 reste, texte_uce, suite = self.decouper(suite, self.ucesize + 15, self.ucesize)
1008 #                print 'reste'
1009 #                print reste
1010 #                print 'texte_uce'
1011 #                print texte_uce
1012 #                print 'suite'
1013 #                print suite
1014
1015             uce = ' '.join([val for val in texte_uce if val not in self.ponctuation_espace])
1016             if uce != '' : 
1017                 print 'RESTEE UUCEEEEEEEEEEEEE', uce
1018                 out.append(uce)
1019             return out
1020         else :
1021             return [' '.join([val for val in txt.split() if val not in self.ponctuation_espace])]
1022
1023 #decouper (list_sep)
1024 #make_uces (decouper)
1025 #treat_txt (make_uces)
1026 #read (treat_txt)
1027
1028 class Builder :
1029     def __init__(self, parent, dlg = None) :
1030         self.parent = parent
1031         self.dlg = dlg
1032         parametres = DoConf(os.path.join(self.parent.UserConfigPath,'corpus.cfg')).getoptions('corpus')
1033         parametres['pathout'] = PathOut(parent.filename, 'corpus').mkdirout()
1034         dial = CorpusPref(parent, parametres)
1035         dial.CenterOnParent()
1036         dial.txtpath.SetLabel(parent.filename)
1037         #dial.repout_choices.SetValue(parametres['pathout'])
1038         self.res = dial.ShowModal()
1039         if self.res == 5100 :
1040             parametres = dial.doparametres()
1041             parametres['originalpath'] = parent.filename
1042             PathOut().createdir(parametres['pathout'])
1043             ReadLexique(self.parent, lang = parametres['lang'])
1044             self.parent.expressions = ReadDicoAsDico(self.parent.DictPath.get(parametres['lang']+'_exp', 'french_exp'))
1045             self.parametres = parametres
1046         dial.Destroy()
1047
1048     def doanalyse(self) :
1049         return BuildFromAlceste(self.parent.filename, self.parametres, self.parent.lexique, self.parent.expressions, dlg = self.dlg).corpus
1050
1051
1052 if __name__ == '__main__' :
1053     t1 = time()
1054     parametres = {'formesdb':'formes.db', 'ucesdb': 'uces.db', 'corpusdb' : 'corpus.db', 'syscoding' : 'utf-8', 'encoding' : encoding}
1055     intro = BuildCorpus(infile, parametres)#, tar_in, tar_infouce)#, tar_formes)
1056     print time() - t1