1"""
2Grammalecte - Lexicographe
3"""
4
5# License: MPL 2
6
7
8import re
9import traceback
10
11
12_dTAGS = {
13    ':N': (" nom,", "Nom"),
14    ':A': (" adjectif,", "Adjectif"),
15    ':M1': (" prénom,", "Prénom"),
16    ':M2': (" patronyme,", "Patronyme, matronyme, nom de famille…"),
17    ':MP': (" nom propre,", "Nom propre"),
18    ':W': (" adverbe,", "Adverbe"),
19    ':J': (" interjection,", "Interjection"),
20    ':B': (" nombre,", "Nombre"),
21    ':T': (" titre,", "Titre de civilité"),
22
23    ':e': (" épicène", "épicène"),
24    ':m': (" masculin", "masculin"),
25    ':f': (" féminin", "féminin"),
26    ':s': (" singulier", "singulier"),
27    ':p': (" pluriel", "pluriel"),
28    ':i': (" invariable", "invariable"),
29
30    ':V1': (" verbe (1ᵉʳ gr.),", "Verbe du 1ᵉʳ groupe"),
31    ':V2': (" verbe (2ᵉ gr.),", "Verbe du 2ᵉ groupe"),
32    ':V3': (" verbe (3ᵉ gr.),", "Verbe du 3ᵉ groupe"),
33    ':V0e': (" verbe,", "Verbe auxiliaire être"),
34    ':V0a': (" verbe,", "Verbe auxiliaire avoir"),
35
36    ':Y': (" infinitif,", "infinitif"),
37    ':P': (" participe présent,", "participe présent"),
38    ':Q': (" participe passé,", "participe passé"),
39    ':Ip': (" présent,", "indicatif présent"),
40    ':Iq': (" imparfait,", "indicatif imparfait"),
41    ':Is': (" passé simple,", "indicatif passé simple"),
42    ':If': (" futur,", "indicatif futur"),
43    ':K': (" conditionnel présent,", "conditionnel présent"),
44    ':Sp': (" subjonctif présent,", "subjonctif présent"),
45    ':Sq': (" subjonctif imparfait,", "subjonctif imparfait"),
46    ':E': (" impératif,", "impératif"),
47
48    ':1s': (" 1ʳᵉ p. sg.,", "verbe : 1ʳᵉ personne du singulier"),
49    ':1ŝ': (" présent interr. 1ʳᵉ p. sg.,", "verbe : 1ʳᵉ personne du singulier (présent interrogatif)"),
50    ':1ś': (" présent interr. 1ʳᵉ p. sg.,", "verbe : 1ʳᵉ personne du singulier (présent interrogatif)"),
51    ':2s': (" 2ᵉ p. sg.,", "verbe : 2ᵉ personne du singulier"),
52    ':3s': (" 3ᵉ p. sg.,", "verbe : 3ᵉ personne du singulier"),
53    ':1p': (" 1ʳᵉ p. pl.,", "verbe : 1ʳᵉ personne du pluriel"),
54    ':2p': (" 2ᵉ p. pl.,", "verbe : 2ᵉ personne du pluriel"),
55    ':3p': (" 3ᵉ p. pl.,", "verbe : 3ᵉ personne du pluriel"),
56    ':3p!': (" 3ᵉ p. pl.,", "verbe : 3ᵉ personne du pluriel (prononciation distinctive)"),
57
58    ':G': ("", "Mot grammatical"),
59    ':X': (" adverbe de négation,", "Adverbe de négation"),
60    ':U': (" adverbe interrogatif,", "Adverbe interrogatif"),
61    ':R': (" préposition,", "Préposition"),
62    ':Rv': (" préposition verbale,", "Préposition verbale"),
63    ':D': (" déterminant,", "Déterminant"),
64    ':Dd': (" déterminant démonstratif,", "Déterminant démonstratif"),
65    ':De': (" déterminant exclamatif,", "Déterminant exclamatif"),
66    ':Dp': (" déterminant possessif,", "Déterminant possessif"),
67    ':Di': (" déterminant indéfini,", "Déterminant indéfini"),
68    ':Dn': (" déterminant négatif,", "Déterminant négatif"),
69    ':Od': (" pronom démonstratif,", "Pronom démonstratif"),
70    ':Oi': (" pronom indéfini,", "Pronom indéfini"),
71    ':On': (" pronom indéfini négatif,", "Pronom indéfini négatif"),
72    ':Ot': (" pronom interrogatif,", "Pronom interrogatif"),
73    ':Or': (" pronom relatif,", "Pronom relatif"),
74    ':Ow': (" pronom adverbial,", "Pronom adverbial"),
75    ':Os': (" pronom personnel sujet,", "Pronom personnel sujet"),
76    ':Oo': (" pronom personnel objet,", "Pronom personnel objet"),
77    ':Ov': (" préverbe,", "Préverbe (pronom personnel objet, +ne)"),
78    ':O1': (" 1ʳᵉ pers.,", "Pronom : 1ʳᵉ personne"),
79    ':O2': (" 2ᵉ pers.,", "Pronom : 2ᵉ personne"),
80    ':O3': (" 3ᵉ pers.,", "Pronom : 3ᵉ personne"),
81    ':C': (" conjonction,", "Conjonction"),
82    ':Ĉ': (" conjonction (él.),", "Conjonction (élément)"),
83    ':Cc': (" conjonction de coordination,", "Conjonction de coordination"),
84    ':Cs': (" conjonction de subordination,", "Conjonction de subordination"),
85    ':Ĉs': (" conjonction de subordination (él.),", "Conjonction de subordination (élément)"),
86
87    ':ÉN': (" locution nominale (él.),", "Locution nominale (élément)"),
88    ':ÉA': (" locution adjectivale (él.),", "Locution adjectivale (élément)"),
89    ':ÉV': (" locution verbale (él.),", "Locution verbale (élément)"),
90    ':ÉW': (" locution adverbiale (él.),", "Locution adverbiale (élément)"),
91    ':ÉR': (" locution prépositive (él.),", "Locution prépositive (élément)"),
92    ':ÉJ': (" locution interjective (él.),", "Locution interjective (élément)"),
93
94    ':Zp': (" préfixe,", "Préfixe"),
95    ':Zs': (" suffixe,", "Suffixe"),
96
97    ':H': ("", "<Hors-norme, inclassable>"),
98
99    ':@': ("", "<Caractère non alpha-numérique>"),
100    ':@p': ("signe de ponctuation", "Signe de ponctuation"),
101    ':@s': ("signe", "Signe divers"),
102
103    ';S': (" : symbole (unité de mesure)", "Symbole (unité de mesure)"),
104
105    '/*': ("", "Sous-dictionnaire <Commun>"),
106    '/C': (" <classique>", "Sous-dictionnaire <Classique>"),
107    '/M': ("", "Sous-dictionnaire <Moderne>"),
108    '/R': (" <réforme>", "Sous-dictionnaire <Réforme 1990>"),
109    '/A': ("", "Sous-dictionnaire <Annexe>"),
110    '/X': ("", "Sous-dictionnaire <Contributeurs>")
111}
112
113_dPFX = {
114    'd': "(de), déterminant épicène invariable",
115    'l': "(le/la), déterminant masculin/féminin singulier",
116    'j': "(je), pronom personnel sujet, 1ʳᵉ pers., épicène singulier",
117    'm': "(me), pronom personnel objet, 1ʳᵉ pers., épicène singulier",
118    't': "(te), pronom personnel objet, 2ᵉ pers., épicène singulier",
119    's': "(se), pronom personnel objet, 3ᵉ pers., épicène singulier/pluriel",
120    'n': "(ne), adverbe de négation",
121    'c': "(ce), pronom démonstratif, masculin singulier/pluriel",
122    'ç': "(ça), pronom démonstratif, masculin singulier",
123    'qu': "(que), conjonction de subordination",
124    'lorsqu': "(lorsque), conjonction de subordination",
125    'puisqu': "(puisque), conjonction de subordination",
126    'quoiqu': "(quoique), conjonction de subordination",
127    'jusqu': "(jusque), préposition",
128}
129
130_dAD = {
131    'je': " pronom personnel sujet, 1ʳᵉ pers. sing.",
132    'tu': " pronom personnel sujet, 2ᵉ pers. sing.",
133    'il': " pronom personnel sujet, 3ᵉ pers. masc. sing.",
134    'on': " pronom personnel sujet, 3ᵉ pers. sing. ou plur.",
135    'elle': " pronom personnel sujet, 3ᵉ pers. fém. sing.",
136    'nous': " pronom personnel sujet/objet, 1ʳᵉ pers. plur.",
137    'vous': " pronom personnel sujet/objet, 2ᵉ pers. plur.",
138    'ils': " pronom personnel sujet, 3ᵉ pers. masc. plur.",
139    'elles': " pronom personnel sujet, 3ᵉ pers. masc. plur.",
140
141    "là": " particule démonstrative",
142    "ci": " particule démonstrative",
143
144    'le': " COD, masc. sing.",
145    'la': " COD, fém. sing.",
146    'les': " COD, plur.",
147
148    'moi': " COI (à moi), sing.",
149    'toi': " COI (à toi), sing.",
150    'lui': " COI (à lui ou à elle), sing.",
151    'nous2': " COI (à nous), plur.",
152    'vous2': " COI (à vous), plur.",
153    'leur': " COI (à eux ou à elles), plur.",
154
155    'y': " pronom adverbial",
156    "m'y": " (me) pronom personnel objet + (y) pronom adverbial",
157    "t'y": " (te) pronom personnel objet + (y) pronom adverbial",
158    "s'y": " (se) pronom personnel objet + (y) pronom adverbial",
159
160    'en': " pronom adverbial",
161    "m'en": " (me) pronom personnel objet + (en) pronom adverbial",
162    "t'en": " (te) pronom personnel objet + (en) pronom adverbial",
163    "s'en": " (se) pronom personnel objet + (en) pronom adverbial",
164}
165
166
167class Lexicographe:
168    "Lexicographer - word analyzer"
169
170    def __init__ (self, oSpellChecker):
171        self.oSpellChecker = oSpellChecker
172        self._zElidedPrefix = re.compile("(?i)^([dljmtsncç]|quoiqu|lorsqu|jusqu|puisqu|qu)['’](.+)")
173        self._zCompoundWord = re.compile("(?i)(\\w+)-((?:les?|la)-(?:moi|toi|lui|[nv]ous|leur)|t-(?:il|elle|on)|y|en|[mts][’'](?:y|en)|les?|l[aà]|[mt]oi|leur|lui|je|tu|ils?|elles?|on|[nv]ous)$")
174        self._zTag = re.compile("[:;/][\\w*][^:;/]*")
175
176    def analyzeWord (self, sWord):
177        "returns a tuple (a list of morphologies, a set of verb at infinitive form)"
178        try:
179            if not sWord:
180                return (None, None)
181            if sWord.count("-") > 4:
182                return (["élément complexe indéterminé"], None)
183            if sWord.isdigit():
184                return (["nombre"], None)
185
186            aMorph = []
187            # préfixes élidés
188            m = self._zElidedPrefix.match(sWord)
189            if m:
190                sWord = m.group(2)
191                aMorph.append( "{}’ : {}".format(m.group(1), _dPFX.get(m.group(1).lower(), "[?]")) )
192            # mots composés
193            m2 = self._zCompoundWord.match(sWord)
194            if m2:
195                sWord = m2.group(1)
196            # Morphologies
197            lMorph = self.oSpellChecker.getMorph(sWord)
198            if len(lMorph) > 1:
199                # sublist
200                aMorph.append( (sWord, [ self.formatTags(s)  for s in lMorph  if ":" in s ]) )
201            elif len(lMorph) == 1:
202                aMorph.append( "{} : {}".format(sWord, self.formatTags(lMorph[0])) )
203            else:
204                aMorph.append( "{} :  inconnu du dictionnaire".format(sWord) )
205            # suffixe d’un mot composé
206            if m2:
207                aMorph.append( "-{} : {}".format(m2.group(2), self._formatSuffix(m2.group(2).lower())) )
208            # Verbes
209            aVerb = { s[1:s.find("/")]  for s in lMorph  if ":V" in s }
210            return (aMorph, aVerb)
211        except (IndexError, TypeError):
212            traceback.print_exc()
213            return (["#erreur"], None)
214
215    def formatTags (self, sTags):
216        "returns string: readable tags"
217        sRes = ""
218        sTags = re.sub("(?<=V[1-3])[itpqnmr_eaxz]+", "", sTags)
219        sTags = re.sub("(?<=V0[ea])[itpqnmr_eaxz]+", "", sTags)
220        for m in self._zTag.finditer(sTags):
221            sRes += _dTAGS.get(m.group(0), " [{}]".format(m.group(0)))[0]
222        if sRes.startswith(" verbe") and not sRes.endswith("infinitif"):
223            sRes += " [{}]".format(sTags[1:sTags.find("/")])
224        return sRes.rstrip(",")
225
226    def _formatSuffix (self, s):
227        if s.startswith("t-"):
228            return "“t” euphonique +" + _dAD.get(s[2:], "[?]")
229        if not "-" in s:
230            return _dAD.get(s.replace("’", "'"), "[?]")
231        if s.endswith("ous"):
232            s += '2'
233        nPos = s.find("-")
234        return "%s +%s" % (_dAD.get(s[:nPos], "[?]"), _dAD.get(s[nPos+1:], "[?]"))
235