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