...
[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 parse_active(self, gramact, gramsup = None) :
438         log.info('parse actives')
439         for lem in self.lems :
440             if self.lems[lem].gram in gramact :
441                 self.lems[lem].act = 1
442             elif gramsup is not None :
443                 if self.lems[lem].gram in gramsup :
444                     self.lems[lem].act = 2
445                 else :
446                     self.lems[lem].act =  0
447             else :
448                 self.lems[lem].act = 2
449
450     def make_actives_limit(self, limit) :
451         if self.idformes is None :
452             self.make_idformes()
453         return [lem for lem in self.lems if self.getlemeff(lem) >= limit]
454     
455     def make_actives_nb(self, nbmax, key) :
456         log.info('make_actives_nb : %i - %i' % (nbmax,key))
457         if self.idformes is None :
458             self.make_idformes()
459         allactives = [[self.lems[lem].freq, lem] for lem in self.lems if self.lems[lem].act == key and self.lems[lem].freq >= 3]
460         self.activenb = len(allactives)
461         allactives = sorted(allactives, reverse = True)
462         if len(allactives) <= nbmax :
463             log.info('nb = %i - eff min = %i ' % (len(allactives), allactives[-1][0]))
464             return [val[1] for val in allactives], allactives[-1][0]
465         else :
466             effs = [val[0] for val in allactives]
467             if effs.count(effs[nbmax - 1]) > 1 :
468                 lim = effs[nbmax - 1] + 1
469                 nok = True
470                 while nok :
471                     try :
472                         stop = effs.index(lim)
473                         nok = False
474                     except ValueError:
475                         lim -= 1
476             else :
477                 stop = nbmax - 1
478         log.info('nb actives = %i - eff min = %i ' % (stop, lim))
479         return [val[1] for val in allactives[0:stop + 1]], lim
480
481     def make_and_write_profile(self, actives, ucecl, fileout) :
482         log.info('formes/classes')
483         tab = [[lem] + [len(set(self.getlemuces(lem)).intersection(classe)) for classe in ucecl] for lem in actives]
484         tab = [[line[0]] + [`val` for val in line[1:]] for line in tab if sum(line[1:]) >= 3]
485         with open(fileout, 'w') as f :
486             f.write('\n'.join([';'.join(line) for line in tab]).encode(self.parametres['syscoding']))
487
488     def make_etoiles(self) :
489         etoiles = set([])
490         for uci in self.ucis :
491             etoiles.update(uci.etoiles[1:] + uci.paras)
492         return list(etoiles)
493
494     def make_and_write_profile_et(self, ucecl, fileout) :
495         log.info('etoiles/classes')
496         etoiles = self.make_etoiles()
497         with open(fileout, 'w') as f :
498             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']))
499
500     def count_from_list(self, l, d) :
501         for val in l :
502             if val in d :
503                 d[val] += 1
504             else :
505                 d[val] = 1
506         return d
507
508     def find_segments(self, taille_segment, taille_limite) :
509         d = {}
510         for uce in self.getalluces() :
511             uce = uce[1].split()
512             d = self.count_from_list([' '.join(uce[i:i+taille_segment]) for i in range(len(uce)-(taille_segment - 1))], d)
513         l = [[d[val], val] for val in d if d[val] >= 3]
514         del(d)
515         l.sort()
516         if len(l) > taille_limite :
517             l = l[-taille_limite:]
518         return l
519          
520     def make_ucecl_from_R(self, filein) :
521         with open(filein, 'rU') as f :
522             c = f.readlines()
523         c.pop(0)
524         self.lc = []
525         for line in c :
526             line = line.replace('\n', '').replace('"', '').split(';')
527             self.lc.append([int(line[0]) - 1, int(line[1])])
528         classesl = [val[1] for val in self.lc]
529         clnb = max(classesl)
530         self.lc = sorted(self.lc, key=itemgetter(1))
531         self.lc = [[uce[0] for uce in self.lc if uce[1] == i] for i in range(clnb+1)]
532         self.lc0 = self.lc.pop(0)
533         #return ucecl
534
535     def gethapaxbyet(self, etoiles) :
536         hapaxuces = [self.getlemuces(forme)[0] for forme in self.lems if self.lems[forme].freq == 1]
537         hucesdict = {}
538         for uce in hapaxuces :
539             if uce in hucesdict :
540                 hucesdict[uce] += 1
541             else :
542                 hucesdict[uce] = 1
543         etuces = [[] for et in etoiles]
544         for uci in self.ucis :
545             get = list(set(uci.etoiles).intersection(etoiles))
546             if len(get) > 1 :
547                 return '2 variables sur la meme ligne'
548             elif get != [] :
549                 etuces[etoiles.index(get[0])] += [uce.ident for uce in uci.uces]
550         etuces = [set(val) for val in etuces]
551         return [sum([hucesdict[uce] for uce in list(etuce.intersection(hapaxuces))]) for etuce in etuces]
552
553     def gethapaxuces(self) :
554         hapaxuces = [self.getlemuces(forme)[0] for forme in self.lems if self.lems[forme].freq == 1]
555         hapax = [forme for forme in self.lems if self.lems[forme].freq == 1]
556         hucesdict = {}
557         for i,uce in enumerate(hapaxuces) :
558             if uce in hucesdict :
559                 hucesdict[uce][0] += 1
560                 hucesdict[uce][1].append(hapax[i])
561             else :
562                 hucesdict[uce] = [1,[hapax[i]]]
563         huces = {}
564         for uce in hucesdict :
565             if hucesdict[uce][0] in huces :
566                 huces[hucesdict[uce][0]].append(uce)
567             else :
568                 huces[hucesdict[uce][0]] = [uce]
569         huces = zip(huces, huces.values())
570         huces.sort(reverse=True)
571         txt = """
572         <html><body>
573         """
574         for nb in huces[0:4] :
575             txt += "<p><h2>%i hapax par uce</h2><p>\n" % nb[0]
576             for uce in nb[1] :
577                 res = self.getconcorde([uce])
578                 for row in res :
579                     ucetxt = ' ' + row[1] + ' '
580                     uceid = row[0]
581                 for hap in hucesdict[uce][1] :
582                     laforme = self.getforme([forme for forme in self.lems[hap].formes][0]).forme
583                     ucetxt = ucetxt.replace(' '+laforme+' ', ' <font color=red>'+laforme+'</font> ')
584                 txt += '<p><b>' + ' '.join(self.getetbyuceid(uceid)) + '</b></p>'
585                 txt += '<p>'+ucetxt+'</p>\n'
586         txt += """
587         </body></html>
588         """
589         with open('/tmp/testhapxuce.html','w') as f :
590             f.write(txt)
591
592
593 class Uci :
594     def __init__(self, iduci, line, paraset = None) :
595         self.ident = iduci
596         self.etoiles = line.split()
597         self.uces = []
598         if paraset is not None :
599             self.paras = paraset.split()
600         else :
601             self.paras = []
602
603 class Uce :
604     def __init__(self, iduce, idpara, iduci) :
605         self.ident = iduce
606         self.para = idpara
607         self.uci = iduci
608
609 class Word :
610     def __init__(self, word, gramtype, idword, lem = None, freq = None) :
611         self.forme = word
612         self.lem = lem
613         self.gram = gramtype
614         self.ident = idword
615         self.act = 1
616         if freq is not None :
617             self.freq = freq
618         else :
619             self.freq = 1
620
621 class Lem :
622     def __init__(self, parent, forme) :
623         self.formes = {forme.ident : forme.freq}
624         self.gram = forme.gram
625         self.freq = forme.freq
626         self.act = forme.act
627
628     def add_forme(self, forme) :
629         self.formes[forme.ident] = forme.freq
630         self.freq += forme.freq
631
632 def decouperlist(chaine, longueur, longueurOptimale) :
633     """
634         on part du dernier caractère, et on recule jusqu'au début de la chaîne.
635         Si on trouve un '$', c'est fini.
636         Sinon, on cherche le meilleur candidat. C'est-à-dire le rapport poids/distance le plus important.
637     """
638     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]]
639     dsep = dict([[val[0],val[1]] for val in separateurs])
640     trouve = False                 # si on a trouvé un bon séparateur
641     iDecoupe = 0                # indice du caractere ou il faut decouper
642     
643     longueur = min(longueur, len(chaine) - 1)
644     chaineTravail = chaine[:longueur + 1]
645     nbCar = longueur
646     meilleur = ['', 0, 0]        # type, poids et position du meilleur separateur
647     
648     try :
649         indice = chaineTravail.index(u'$')
650         trouve = True
651         iDecoupe = indice
652     except ValueError :
653         pass
654     if not trouve:
655         while nbCar >= 0:
656             caractere = chaineTravail[nbCar]
657             distance = abs(longueurOptimale - nbCar) + 1
658             meilleureDistance = abs(longueurOptimale - meilleur[2]) + 1
659             if caractere in dsep :
660                 if (float(dsep[caractere]) / distance) > (float(meilleur[1]) / meilleureDistance) :
661                     meilleur[0] = caractere
662                     meilleur[1] = dsep[caractere]
663                     meilleur[2] = nbCar
664                     trouve = True
665                     iDecoupe = nbCar
666             else :
667                 if (float(dsep[' ']) / distance) > (float(meilleur[1]) / meilleureDistance) :
668                     meilleur[0] = caractere
669                     meilleur[1] = dsep[' ']
670                     meilleur[2] = nbCar
671                     trouve = True
672                     iDecoupe = nbCar
673             nbCar = nbCar - 1
674     # si on a trouvé
675     if trouve:
676         fin = chaine[iDecoupe + 1:]
677         retour = chaineTravail[:iDecoupe]
678         return len(retour) > 0, retour, fin
679     # si on a rien trouvé
680     return False, chaine, ''
681
682 def testetoile(line) :
683     return line.startswith(u'****')
684
685 def testint(line) :
686     return line[0:4].isdigit() and u'*' in line
687
688 def prep_txtlist(txt) :
689     return txt.split() + [u'$']
690
691 def prep_txtcharact(txt) :
692     return txt + u'$'
693
694 class BuildCorpus :
695     """
696     Class for building a corpus
697     """
698     def __init__(self, infile, parametres_corpus, lexique = None, expressions = None, dlg = None) :
699         log.info('begin building corpus...')
700         self.lexique = lexique
701         self.expressions = expressions
702         self.dlg = dlg
703         self.corpus = Corpus(self, parametres_corpus)
704         self.infile = infile
705         self.last = 0
706         self.lim = parametres_corpus.get('lim', 1000000)
707         self.encoding = parametres_corpus['encoding']
708         self.corpus.pathout = PathOut(filename = parametres_corpus['originalpath'], dirout = parametres_corpus['pathout'])
709         self.corpus.pathout.createdir(parametres_corpus['pathout'])
710         self.corpus.parametres['uuid'] = str(uuid4())
711         self.corpus.parametres['corpus_name'] = os.path.split(self.corpus.parametres['pathout'])[1]
712         self.corpus.parametres['type'] = 'corpus'
713         if self.corpus.parametres['keep_ponct'] :
714             self.ponctuation_espace = [' ', '']
715         else :
716             self.ponctuation_espace =  [' ','.', u'£', ';', '?', '!', ',', ':','']
717         self.cleans = []
718         self.tolist = self.corpus.parametres.get('tolist', 0)
719         self.buildcleans()
720         self.prep_makeuce()
721         #create database
722         self.connect()
723         self.dobuild()
724
725     def prep_makeuce(self) :
726         method = self.corpus.parametres.get('ucemethod', 0)
727         if method == 1 :
728             self.decouper = decouperlist
729             self.prep_txt = prep_txtlist
730             self.ucesize = self.corpus.parametres.get('ucesize', 40)
731         elif method == 0 :
732             self.decouper = decoupercharact
733             self.prep_txt = prep_txtcharact
734             self.ucesize = self.corpus.parametres.get('ucesize', 240)
735         log.info('method uce : %s' % method)
736
737     def dobuild(self) :    
738         t1 = time()
739         self.read_corpus(self.infile)
740         self.indexdb()
741         self.corpus.parametres['ira'] = self.corpus.pathout['Corpus.cira']
742         self.time = time() - t1
743         self.dofinish()
744         DoConf().makeoptions(['corpus'],[self.corpus.parametres], self.corpus.pathout['Corpus.cira'])
745         log.info('time : %f' % (time() - t1))
746
747     def connect(self) :
748         self.conn_f = sqlite3.connect(self.corpus.pathout['formes.db'])
749         self.cf = self.conn_f.cursor()
750         self.cf.execute('CREATE TABLE IF NOT EXISTS uces (id INTEGER, uces TEXT);')
751         self.cf.execute('CREATE TABLE IF NOT EXISTS eff (id INTEGER, eff TEXT);')
752         self.conn_f.commit()
753         self.cf = self.conn_f.cursor()
754         self.cf.execute('PRAGMA temp_store=MEMORY;')
755         self.cf.execute('PRAGMA journal_mode=MEMORY;')
756         self.cf.execute('PRAGMA  synchronous = OFF;')
757         self.cf.execute('begin')
758         self.conn = sqlite3.connect(self.corpus.pathout['uces.db'])
759         self.c = self.conn.cursor()
760         self.c.execute('CREATE TABLE IF NOT EXISTS uces (id INTEGER, uces TEXT);')
761         self.conn.commit()
762         self.c = self.conn.cursor()
763         self.c.execute('PRAGMA temp_store=MEMORY;')
764         self.c.execute('PRAGMA journal_mode=MEMORY;')
765         self.c.execute('PRAGMA  synchronous = OFF;')
766         self.c.execute('begin')
767
768     def indexdb(self) :
769         #commit index and close db
770         self.conn.commit()
771         self.conn_f.commit()
772         self.cf.execute('CREATE INDEX iduces ON uces (id);')
773         self.cf.execute('CREATE INDEX ideff ON eff (id);')
774         self.c.close()
775         self.cf.close()
776         #backup corpora
777         self.conn_corpus = sqlite3.connect(self.corpus.pathout['corpus.db'])
778         self.ccorpus = self.conn_corpus.cursor()
779         self.ccorpus.execute('CREATE TABLE IF NOT EXISTS etoiles (uci INTEGER, et TEXT, paras TEXT);')
780         self.ccorpus.execute('CREATE TABLE IF NOT EXISTS luces (uci INTEGER, para INTEGER, uce INTEGER);')
781         self.ccorpus.execute('CREATE TABLE IF NOT EXISTS formes (ident INTEGER, forme TEXT, lem TEXT, gram TEXT, freq INTEGER);')
782         self.conn_corpus.commit()
783         self.ccorpus = self.conn_corpus.cursor()
784         self.ccorpus.execute('PRAGMA temp_store=MEMORY;')
785         self.ccorpus.execute('PRAGMA journal_mode=MEMORY;')
786         self.ccorpus.execute('PRAGMA  synchronous = OFF;')
787         self.ccorpus.execute('begin')
788         self.backup_corpus()
789         self.ccorpus.execute('CREATE INDEX iduci ON luces (uci);')
790         self.conn_corpus.commit()
791         self.conn_corpus.close()
792         #self.corpus.parametres['corpus_ira'] = self.corpus.pathout['corpus.cira']
793
794     def buildcleans(self) :
795         if self.corpus.parametres.get('lower', 1) :
796             self.cleans.append(self.dolower)
797         if self.corpus.parametres.get('firstclean', 1) :
798             self.cleans.append(self.firstclean)
799         self.rule = self.corpus.parametres.get('keep_caract', u"^a-zA-Z0-9àÀâÂäÄáÁéÉèÈêÊëËìÌîÎïÏòÒôÔöÖùÙûÛüÜçÇßœŒ’ñ.:,;!?*'_-")
800         self.cleans.append(self.docharact)
801         if self.corpus.parametres.get('expressions', 1) :
802             self.cleans.append(self.make_expression)
803         if self.corpus.parametres.get('apos', 1) :
804             self.cleans.append(self.doapos)
805         if self.corpus.parametres.get('tiret', 1):
806             self.cleans.append(self.dotiret)
807
808     def make_expression(self,txt) :
809          for expression in self.expressions:
810             if expression in txt :
811                 txt = txt.replace(expression, self.expressions[expression][0])
812          return txt
813     
814     def dolower(self, txt) :
815         return txt.lower()
816
817     def docharact(self, txt) :
818         #rule = u"^a-zA-Z0-9àÀâÂäÄáÁéÉèÈêÊëËìÌîÎïÏòÒôÔöÖùÙûÛüÜçÇßœŒ’ñ.:,;!?*'_-"
819         list_keep = u"[" + self.rule + "]+"
820         return re.sub(list_keep, ' ', txt)
821     
822     def doapos(self, txt) :
823         return txt.replace(u'\'', u' ')
824
825     def dotiret(self, txt) :
826         return txt.replace(u'-', u' ')
827
828     def firstclean(self, txt) :
829         txt = txt.replace(u'’',"'")
830         txt = txt.replace(u'œ', u'oe')
831         return txt.replace('...',u' £ ').replace('?',' ? ').replace('.',' . ').replace('!', ' ! ').replace(',',' , ').replace(';', ' ; ').replace(':',' : ')
832
833     def make_cleans(self, txt) :
834         for clean in self.cleans :
835             txt = clean(txt)
836         return txt
837
838     def backup_uce(self) :
839         if self.corpus.idformesuces != {} :
840             log.info('backup %i' % len(self.corpus.idformesuces))
841             touce = [(`forme`, ' '.join([`val` for val in  self.corpus.idformesuces[forme].keys()])) for forme in self.corpus.idformesuces]
842             toeff = [(`forme`, ' '.join([`val` for val in  self.corpus.idformesuces[forme].values()])) for forme in self.corpus.idformesuces]
843             self.cf.executemany('INSERT INTO uces VALUES (?,?);', touce)
844             self.cf.executemany('INSERT INTO eff VALUES (?,?);', toeff)
845         self.corpus.idformesuces = {}        
846         self.count = 1
847
848     def backup_corpus(self) :
849         log.info('start backup corpus')
850         t = time()
851         for uci in self.corpus.ucis :
852             self.ccorpus.execute('INSERT INTO etoiles VALUES (?,?,?);' ,(uci.ident,' '.join(uci.etoiles), ' '.join(uci.paras,)))
853             for uce in uci.uces : 
854                 self.ccorpus.execute('INSERT INTO luces VALUES (?,?,?);',(`uci.ident`,`uce.para`,`uce.ident`,))
855         for forme in self.corpus.formes :
856             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`,))
857         log.info('%f' % (time() - t))
858
859     def dofinish(self) :
860         self.corpus.parametres['date'] = datetime.datetime.now().ctime()
861         minutes, seconds = divmod(self.time, 60)
862         hours, minutes = divmod(minutes, 60)
863         self.corpus.parametres['time'] = '%.0fh %.0fm %.0fs' % (hours, minutes, seconds)
864         self.corpus.parametres['ucinb'] = self.corpus.getucinb()
865         self.corpus.parametres['ucenb'] = self.corpus.getucenb()
866         self.corpus.parametres['occurrences'] = self.corpus.gettotocc()
867         self.corpus.parametres['formesnb'] = len(self.corpus.formes)
868         hapaxnb = self.corpus.gethapaxnb()
869         pourhapaxf = (float(hapaxnb) / len(self.corpus.formes)) * 100
870         pourhapaxocc = (float(hapaxnb) / self.corpus.parametres['occurrences']) * 100
871         self.corpus.parametres['hapax'] = '%i - %.2f %% des formes - %.2f %% des occurrences' % (hapaxnb, pourhapaxf, pourhapaxocc)
872
873
874 class BuildFromAlceste(BuildCorpus) :
875     #def __init___(self, infile, parametres_corpus) :
876     #    BuildCorpus.__init__(self, infile, parametres_corpus)
877
878
879     def read_corpus(self, infile) :
880         self.limitshow = 0
881         self.count = 1
882         if self.corpus.parametres['ucimark'] == 0 :
883             self.testuci = testetoile
884         elif  self.corpus.parametres['ucimark'] == 1 :
885             self.testuci = testint
886         txt = []
887         iduci = -1
888         idpara = -1
889         iduce = -1
890         with codecs.open(infile, 'rU', self.encoding) as f :
891             for line in f :
892                 if self.testuci(line) :
893                     iduci += 1
894                     if txt != [] :
895                         iduce, idpara = self.treattxt(txt, iduce, idpara, iduci - 1)
896                         txt = []
897                         self.corpus.ucis.append(Uci(iduci, line))
898                     else :
899                         self.corpus.ucis.append(Uci(iduci, line))
900                 elif line.startswith(u'-*') :
901                     if txt != [] :
902                         iduce, idpara = self.treattxt(txt, iduce, idpara, iduci)
903                         txt = []
904                     idpara += 1
905                     self.corpus.ucis[-1].paras.append(line.split()[0])
906                 elif line.strip() != '' and iduci != -1 :
907                     txt.append(line)
908         if txt != [] :
909             iduce, idpara = self.treattxt(txt, iduce, idpara, iduci)
910             del(txt)
911         self.backup_uce()
912
913     def treattxt(self, txt, iduce, idpara, iduci) :
914         txt = ' '.join(txt)
915         #log.debug('ATTENTION CHINOIS -> charactères')
916         #clean_chinois = [self.firstclean, self.dolower, self.make_expression, self.doapos, self.dotiret]
917         #log.debug('ATTENTION CHINOIS -> list(text)')
918         #txt = ' '.join(list(txt))
919         txt = self.make_cleans(txt)#, clean_chinois)
920         ucetxt = self.make_uces(txt, self.corpus.parametres['douce'])
921         if self.corpus.ucis[-1].paras == [] :
922             idpara += 1
923         for uce in ucetxt :
924             iduce += 1
925             self.corpus.ucis[-1].uces.append(Uce(iduce, idpara, iduci))
926             self.c.execute('INSERT INTO uces VALUES(?,?);', (`iduce`,uce))
927             if not self.tolist :
928                 uce = uce.split()
929             else :
930                 uce = list(uce)
931             for word in uce :
932                 self.last += 1
933                 self.corpus.add_word(word)
934         if self.dlg is not None :
935             if self.limitshow > self.count :
936                 self.dlg.Pulse('uci: %i - uce : %i' % (iduci + 1, iduce +1))
937                 self.count += 1
938                 self.limitshow = 0
939             else :
940                 self.limitshow = self.last / 100000
941         log.debug(`iduci`, `idpara`, `iduce`)
942         if self.last > self.lim :
943             self.backup_uce()
944             self.last = 0
945         return iduce, idpara
946
947     def make_uces(self, txt, douce = True, keep_ponct = False) :
948         txt = ' '.join(txt.split())
949         if douce :
950             out = []
951             reste, texte_uce, suite = self.decouper(self.prep_txt(txt), self.ucesize + 15, self.ucesize)
952 #            print 'reste'
953 #            print reste
954 #            print 'texte_uce'
955 #            print texte_uce
956 #            print 'suite'
957 #            print suite
958             while reste :
959                 uce = ' '.join([val for val in texte_uce if val not in self.ponctuation_espace])
960                 if uce != '' :
961                     out.append(uce)
962                 reste, texte_uce, suite = self.decouper(suite, self.ucesize + 15, self.ucesize)
963 #                print 'reste'
964 #                print reste
965 #                print 'texte_uce'
966 #                print texte_uce
967 #                print 'suite'
968 #                print suite
969
970             uce = ' '.join([val for val in texte_uce if val not in self.ponctuation_espace])
971             if uce != '' : 
972                 print 'RESTEE UUCEEEEEEEEEEEEE', uce
973                 out.append(uce)
974             return out
975         else :
976             return [' '.join([val for val in txt.split() if val not in self.ponctuation_espace])]
977
978 #decouper (list_sep)
979 #make_uces (decouper)
980 #treat_txt (make_uces)
981 #read (treat_txt)
982
983 class Builder :
984     def __init__(self, parent, dlg = None) :
985         self.parent = parent
986         self.dlg = dlg
987         parametres = DoConf(os.path.join(self.parent.UserConfigPath,'corpus.cfg')).getoptions('corpus')
988         parametres['pathout'] = PathOut(parent.filename, 'corpus').mkdirout()
989         dial = CorpusPref(parent, parametres)
990         dial.CenterOnParent()
991         dial.txtpath.SetLabel(parent.filename)
992         #dial.repout_choices.SetValue(parametres['pathout'])
993         self.res = dial.ShowModal()
994         if self.res == 5100 :
995             parametres = dial.doparametres()
996             parametres['originalpath'] = parent.filename
997             PathOut().createdir(parametres['pathout'])
998             ReadLexique(self.parent, lang = parametres['lang'])
999             self.parent.expressions = ReadDicoAsDico(self.parent.DictPath.get(parametres['lang']+'_exp', 'french_exp'))
1000             self.parametres = parametres
1001         dial.Destroy()
1002
1003     def doanalyse(self) :
1004         return BuildFromAlceste(self.parent.filename, self.parametres, self.parent.lexique, self.parent.expressions, dlg = self.dlg).corpus
1005
1006
1007 if __name__ == '__main__' :
1008     t1 = time()
1009     parametres = {'formesdb':'formes.db', 'ucesdb': 'uces.db', 'corpusdb' : 'corpus.db', 'syscoding' : 'utf-8', 'encoding' : encoding}
1010     intro = BuildCorpus(infile, parametres)#, tar_in, tar_infouce)#, tar_formes)
1011     print time() - t1