Grammalecte  Changes On Branch ba6939effa5af5b1

Changes In Branch rg Through [ba6939effa] Excluding Merge-Ins

This is equivalent to a diff from cb3f319c08 to ba6939effa

2018-09-12
09:46
[core][build][js] fix several issues, better debugging information, create RegExp at runtime instead of preprocessing them at build check-in: 50bef581ca user: olr tags: build, core, rg
09:44
[core][py] gc engine: better debugging information check-in: ba6939effa user: olr tags: core, rg
08:05
[build] update code conversion to JS check-in: 0c1e2728dd user: olr tags: build, rg
2018-06-25
07:58
[fr] faux positif: en tant que président du conseil (trailing spaces automatically removed) check-in: 37fb199673 user: olr tags: fr, trunk
2018-06-24
19:03
merge trunk check-in: 099647c959 user: olr tags: rg
2018-06-22
07:46
[cli] option to load personal dictionary check-in: cb3f319c08 user: olr tags: cli, trunk
2018-06-15
20:44
[fr] faux positif: accord de laisser avec les pronoms sans impératif check-in: 24d41be12e user: olr tags: fr, trunk

Modified compile_rules.py from [1ea2b6d97a] to [2aa727e4cf].




1
2
3
4
5
6

7
8
9
10
11
12
13
14
15
16
17
18
19
20













21

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
..
95
96
97
98
99
100
101

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117









118
119
120
121
122
123
124
125
126
127
128
129
130
131
...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
...
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
...
223
224
225
226
227
228
229















230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
...
270
271
272
273
274
275
276

277
278
279
280
281
282
283
284
285
286
287
288
289

290

291
292
293
294
295
296
297
298
299
300
301
302
303







304

305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333

334
335
336
337
338
339
340
341
342
343
344
345

346
347

348
349
350
351
352
353

354
355
356
357
358
359
360
...
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
...
413
414
415
416
417
418
419

420
421
422
423
424
425
426
...
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445

446
447
448

449
450
451
452
453
454
455

456
457
458
459
460
461
462

463
464

465
466

467
468
469
470
471

472
473
474






















475

476
477

478
479
480
481
482
483
484
...
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523

524
525
526
527
528
529
530
531
532
533

534
535

536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554




555




import re
import traceback
import json

import compile_rules_js_convert as jsconv



dDEF = {}
lFUNCTIONS = []

aRULESET = set()     # set of rule-ids to check if there is several rules with the same id
nRULEWITHOUTNAME = 0

dJSREGEXES = {}

sWORDLIMITLEFT  = r"(?<![\w.,–-])"   # r"(?<![-.,—])\b"  seems slower
sWORDLIMITRIGHT = r"(?![\w–-])"      # r"\b(?!-—)"       seems slower















def prepareFunction (s):

    s = s.replace("__also__", "bCondMemo")
    s = s.replace("__else__", "not bCondMemo")
    s = re.sub(r"isStart *\(\)", 'before("^ *$|, *$")', s)
    s = re.sub(r"isRealStart *\(\)", 'before("^ *$")', s)
    s = re.sub(r"isStart0 *\(\)", 'before0("^ *$|, *$")', s)
    s = re.sub(r"isRealStart0 *\(\)", 'before0("^ *$")', s)
    s = re.sub(r"isEnd *\(\)", 'after("^ *$|^,")', s)
    s = re.sub(r"isRealEnd *\(\)", 'after("^ *$")', s)
    s = re.sub(r"isEnd0 *\(\)", 'after0("^ *$|^,")', s)
    s = re.sub(r"isRealEnd0 *\(\)", 'after0("^ *$")', s)
    s = re.sub(r"(select|exclude)[(][\\](\d+)", '\\1(dDA, m.start(\\2), m.group(\\2)', s)
    s = re.sub(r"define[(][\\](\d+)", 'define(dDA, m.start(\\1)', s)
    s = re.sub(r"(morph|morphex|displayInfo)[(][\\](\d+)", '\\1((m.start(\\2), m.group(\\2))', s)
    s = re.sub(r"(morph|morphex|displayInfo)[(]", '\\1(dDA, ', s)
    s = re.sub(r"(sugg\w+|switch\w+)\(@", '\\1(m.group(i[4])', s)
    s = re.sub(r"word\(\s*1\b", 'nextword1(s, m.end()', s)                                  # word(1)
    s = re.sub(r"word\(\s*-1\b", 'prevword1(s, m.start()', s)                               # word(-1)
    s = re.sub(r"word\(\s*(\d)", 'nextword(s, m.end(), \\1', s)                             # word(n)
    s = re.sub(r"word\(\s*-(\d)", 'prevword(s, m.start(), \\1', s)                          # word(-n)
    s = re.sub(r"before\(\s*", 'look(s[:m.start()], ', s)                                   # before(s)
    s = re.sub(r"after\(\s*", 'look(s[m.end():], ', s)                                      # after(s)
    s = re.sub(r"textarea\(\s*", 'look(s, ', s)                                             # textarea(s)
    s = re.sub(r"before_chk1\(\s*", 'look_chk1(dDA, s[:m.start()], 0, ', s)                 # before_chk1(s)
    s = re.sub(r"after_chk1\(\s*", 'look_chk1(dDA, s[m.end():], m.end(), ', s)              # after_chk1(s)
    s = re.sub(r"textarea_chk1\(\s*", 'look_chk1(dDA, s, 0, ', s)                           # textarea_chk1(s)
    s = re.sub(r"/0", 'sx[m.start():m.end()]', s)                                           # /0
    s = re.sub(r"before0\(\s*", 'look(sx[:m.start()], ', s)                                 # before0(s)
    s = re.sub(r"after0\(\s*", 'look(sx[m.end():], ', s)                                    # after0(s)
    s = re.sub(r"textarea0\(\s*", 'look(sx, ', s)                                           # textarea0(s)
    s = re.sub(r"before0_chk1\(\s*", 'look_chk1(dDA, sx[:m.start()], 0, ', s)               # before0_chk1(s)
    s = re.sub(r"after0_chk1\(\s*", 'look_chk1(dDA, sx[m.end():], m.end(), ', s)            # after0_chk1(s)
    s = re.sub(r"textarea0_chk1\(\s*", 'look_chk1(dDA, sx, 0, ', s)                         # textarea0_chk1(s)
    s = re.sub(r"isEndOfNG\(\s*\)", 'isEndOfNG(dDA, s[m.end():], m.end())', s)              # isEndOfNG(s)
    s = re.sub(r"isNextNotCOD\(\s*\)", 'isNextNotCOD(dDA, s[m.end():], m.end())', s)        # isNextNotCOD(s)
    s = re.sub(r"isNextVerb\(\s*\)", 'isNextVerb(dDA, s[m.end():], m.end())', s)            # isNextVerb(s)
    s = re.sub(r"\bspell *[(]", '_oSpellChecker.isValid(', s)
    s = re.sub(r"[\\](\d+)", 'm.group(\\1)', s)
    return s


def uppercase (s, sLang):
    "(flag i is not enough): converts regex to uppercase regex: 'foo' becomes '[Ff][Oo][Oo]', but 'Bar' becomes 'B[Aa][Rr]'."
................................................................................
            nState = 4
        elif nState == 4:
            nState = 0
    return sUp


def countGroupInRegex (sRegex):

    try:
        return re.compile(sRegex).groups
    except:
        traceback.print_exc()
        print(sRegex)
    return 0


def createRule (s, nIdLine, sLang, bParagraph, dOptPriority):
    "returns rule as list [option name, regex, bCaseInsensitive, identifier, list of actions]"
    global dJSREGEXES
    global nRULEWITHOUTNAME

    #### OPTIONS
    sLineId = str(nIdLine) + ("p" if bParagraph else "s")
    sRuleId = sLineId









    sOption = False         # False or [a-z0-9]+ name
    nPriority = 4           # Default is 4, value must be between 0 and 9
    tGroups = None          # code for groups positioning (only useful for JavaScript)
    cCaseMode = 'i'         # i: case insensitive,  s: case sensitive,  u: uppercasing allowed
    cWordLimitLeft = '['    # [: word limit, <: no specific limit
    cWordLimitRight = ']'   # ]: word limit, >: no specific limit
    m = re.match("^__(?P<borders_and_case>[[<]\\w[]>])(?P<option>/[a-zA-Z0-9]+|)(?P<ruleid>\\(\\w+\\)|)(?P<priority>![0-9]|)__ *", s)
    if m:
        cWordLimitLeft = m.group('borders_and_case')[0]
        cCaseMode = m.group('borders_and_case')[1]
        cWordLimitRight = m.group('borders_and_case')[2]
        sOption = m.group('option')[1:]  if m.group('option')  else False
        if m.group('ruleid'):
            sRuleId =  m.group('ruleid')[1:-1]
................................................................................
    #### REGEX TRIGGER
    i = s.find(" <<-")
    if i == -1:
        print("# Error: no condition at line " + sLineId)
        return None
    sRegex = s[:i].strip()
    s = s[i+4:]
    
    # JS groups positioning codes
    m = re.search("@@\\S+", sRegex)
    if m:
        tGroups = jsconv.groupsPositioningCodeToList(sRegex[m.start()+2:])
        sRegex = sRegex[:m.start()].strip()
    # JS regex
    m = re.search("<js>.+</js>i?", sRegex)
................................................................................
        sRegex = sRegex.replace("(?i)", "")
        sRegex = uppercase(sRegex, sLang)
    else:
        print("# Unknown case mode [" + cCaseMode + "] at line " + sLineId)

    ## check regex
    try:
        z = re.compile(sRegex)
    except:
        print("# Regex error at line ", nIdLine)
        print(sRegex)
        traceback.print_exc()
        return None
    ## groups in non grouping parenthesis
    for x in re.finditer("\(\?:[^)]*\([[\w -]", sRegex):
        print("# Warning: groups inside non grouping parenthesis in regex at line " + sLineId)

    #### PARSE ACTIONS
    lActions = []
    nAction = 1
    for sAction in s.split(" <<- "):
        t = createAction(sRuleId + "_" + str(nAction), sAction, nGroup)
................................................................................
        if t:
            lActions.append(t)
    if not lActions:
        return None

    return [sOption, sRegex, bCaseInsensitive, sLineId, sRuleId, nPriority, lActions, tGroups]

















def createAction (sIdAction, sAction, nGroup):
    "returns an action to perform as a tuple (condition, action type, action[, iGroup [, message, URL ]])"
    global lFUNCTIONS

    m = re.search(r"([-~=>])(\d*|)>>", sAction)
    if not m:
        print("# No action at line " + sIdAction)
        return None

    #### CONDITION
    sCondition = sAction[:m.start()].strip()
    if sCondition:
        sCondition = prepareFunction(sCondition)
        lFUNCTIONS.append(("c_"+sIdAction, sCondition))
        for x in re.finditer("[.](?:group|start|end)[(](\d+)[)]", sCondition):
            if int(x.group(1)) > nGroup:
                print("# Error in groups in condition at line " + sIdAction + " ("+str(nGroup)+" groups only)")
        if ".match" in sCondition:
            print("# Error. JS compatibility. Don't use .match() in condition, use .search()")
        sCondition = "c_"+sIdAction
    else:
        sCondition = None

    #### iGroup / positioning
    iGroup = int(m.group(2)) if m.group(2) else 0
    if iGroup > nGroup:
        print("# Selected group > group number in regex at line " + sIdAction)
    
    #### ACTION
    sAction = sAction[m.end():].strip()
    cAction = m.group(1)
    if cAction == "-":
        ## error
        iMsg = sAction.find(" # ")
        if iMsg == -1:
................................................................................
            sMsg = sAction[iMsg+3:].strip()
            sAction = sAction[:iMsg].strip()
            sURL = ""
            mURL = re.search("[|] *(https?://.*)", sMsg)
            if mURL:
                sURL = mURL.group(1).strip()
                sMsg = sMsg[:mURL.start(0)].strip()

            if sMsg[0:1] == "=":
                sMsg = prepareFunction(sMsg[1:])
                lFUNCTIONS.append(("m_"+sIdAction, sMsg))
                for x in re.finditer("group[(](\d+)[)]", sMsg):
                    if int(x.group(1)) > nGroup:
                        print("# Error in groups in message at line " + sIdAction + " ("+str(nGroup)+" groups only)")
                sMsg = "=m_"+sIdAction
            else:
                for x in re.finditer(r"\\(\d+)", sMsg):
                    if int(x.group(1)) > nGroup:
                        print("# Error in groups in message at line " + sIdAction + " ("+str(nGroup)+" groups only)")
                if re.search("[.]\\w+[(]", sMsg):
                    print("# Error in message at line " + sIdAction + ":  This message looks like code. Line should begin with =")

            

    if sAction[0:1] == "=" or cAction == "=":
        if "define" in sAction and not re.search(r"define\(\\\d+ *, *\[.*\] *\)", sAction):
            print("# Error in action at line " + sIdAction + ": second argument for define must be a list of strings")
        sAction = prepareFunction(sAction)
        sAction = sAction.replace("m.group(i[4])", "m.group("+str(iGroup)+")")
        for x in re.finditer("group[(](\d+)[)]", sAction):
            if int(x.group(1)) > nGroup:
                print("# Error in groups in replacement at line " + sIdAction + " ("+str(nGroup)+" groups only)")
    else:
        for x in re.finditer(r"\\(\d+)", sAction):
            if int(x.group(1)) > nGroup:
                print("# Error in groups in replacement at line " + sIdAction + " ("+str(nGroup)+" groups only)")
        if re.search("[.]\\w+[(]|sugg\\w+[(]", sAction):







            print("# Error in action at line " + sIdAction + ":  This action looks like code. Line should begin with =")


    if cAction == "-":
        ## error detected --> suggestion
        if not sAction:
            print("# Error in action at line " + sIdAction + ":  This action is empty.")
        if sAction[0:1] == "=":
            lFUNCTIONS.append(("s_"+sIdAction, sAction[1:]))
            sAction = "=s_"+sIdAction
        elif sAction.startswith('"') and sAction.endswith('"'):
            sAction = sAction[1:-1]
        if not sMsg:
            print("# Error in action at line " + sIdAction + ":  the message is empty.")
        return [sCondition, cAction, sAction, iGroup, sMsg, sURL]
    elif cAction == "~":
        ## text processor
        if not sAction:
            print("# Error in action at line " + sIdAction + ":  This action is empty.")
        if sAction[0:1] == "=":
            lFUNCTIONS.append(("p_"+sIdAction, sAction[1:]))
            sAction = "=p_"+sIdAction
        elif sAction.startswith('"') and sAction.endswith('"'):
            sAction = sAction[1:-1]
        return [sCondition, cAction, sAction, iGroup]
    elif cAction == "=":
        ## disambiguator
        if sAction[0:1] == "=":
            sAction = sAction[1:]
        if not sAction:
            print("# Error in action at line " + sIdAction + ":  This action is empty.")

        lFUNCTIONS.append(("d_"+sIdAction, sAction))
        sAction = "d_"+sIdAction
        return [sCondition, cAction, sAction]
    elif cAction == ">":
        ## no action, break loop if condition is False
        return [sCondition, cAction, ""]
    else:
        print("# Unknown action at line " + sIdAction)
        return None


def _calcRulesStats (lRules):

    d = {'=':0, '~': 0, '-': 0, '>': 0}
    for aRule in lRules:

        for aAction in aRule[6]:
            d[aAction[1]] = d[aAction[1]] + 1
    return (d, len(lRules))


def displayStats (lParagraphRules, lSentenceRules):

    print("  {:>18} {:>18} {:>18} {:>18}".format("DISAMBIGUATOR", "TEXT PROCESSOR", "GRAMMAR CHECKING", "REGEX"))
    d, nRule = _calcRulesStats(lParagraphRules)
    print("§ {:>10} actions {:>10} actions {:>10} actions  in {:>8} rules".format(d['='], d['~'], d['-'], nRule))
    d, nRule = _calcRulesStats(lSentenceRules)
    print("s {:>10} actions {:>10} actions {:>10} actions  in {:>8} rules".format(d['='], d['~'], d['-'], nRule))


................................................................................
            m = re.match("OPTGROUP/([a-z0-9]+):(.+)$", sLine)
            lStructOpt.append( (m.group(1), list(map(str.split, m.group(2).split(",")))) )
        elif sLine.startswith("OPTSOFTWARE:"):
            lOpt = [ [s, {}]  for s in sLine[12:].strip().split() ]  # don’t use tuples (s, {}), because unknown to JS
        elif sLine.startswith("OPT/"):
            m = re.match("OPT/([a-z0-9]+):(.+)$", sLine)
            for i, sOpt in enumerate(m.group(2).split()):
                lOpt[i][1][m.group(1)] =  eval(sOpt)
        elif sLine.startswith("OPTPRIORITY/"):
            m = re.match("OPTPRIORITY/([a-z0-9]+): *([0-9])$", sLine)
            dOptPriority[m.group(1)] = int(m.group(2))
        elif sLine.startswith("OPTLANG/"):
            m = re.match("OPTLANG/([a-z][a-z](?:_[A-Z][A-Z]|)):(.+)$", sLine)
            sLang = m.group(1)[:2]
            dOptLabel[sLang] = { "__optiontitle__": m.group(2).strip() }
................................................................................
    print("  options defined for: " + ", ".join([ t[0] for t in lOpt ]))
    dOptions = { "lStructOpt": lStructOpt, "dOptLabel": dOptLabel, "sDefaultUILang": sDefaultUILang }
    dOptions.update({ "dOpt"+k: v  for k, v in lOpt })
    return dOptions, dOptPriority


def printBookmark (nLevel, sComment, nLine):

    print("  {:>6}:  {}".format(nLine, "  " * nLevel + sComment))


def make (spLang, sLang, bJavaScript):
    "compile rules, returns a dictionary of values"
    # for clarity purpose, don’t create any file here

................................................................................
        lRules = open(spLang + "/rules.grx", 'r', encoding="utf-8").readlines()
    except:
        print("Error. Rules file in project [" + sLang + "] not found.")
        exit()

    # removing comments, zeroing empty lines, creating definitions, storing tests, merging rule lines
    print("  parsing rules...")
    global dDEF
    lLine = []
    lRuleLine = []
    lTest = []
    lOpt = []
    zBookmark = re.compile("^!!+")
    zGraphLink = re.compile(r"^@@@@GRAPHLINK>(\w+)@@@@")

    for i, sLine in enumerate(lRules, 1):
        if sLine.startswith('#END'):

            printBookmark(0, "BREAK BY #END", i)
            break
        elif sLine.startswith("#"):

            pass
        elif sLine.startswith("@@@@"):
            m = re.match(r"^@@@@GRAPHLINK>(\w+)@@@@", sLine.strip())
            if m:
                #lRuleLine.append(["@GRAPHLINK", m.group(1)])
                printBookmark(1, "@GRAPHLINK: " + m.group(1), i)
        elif sLine.startswith("DEF:"):

            m = re.match("DEF: +([a-zA-Z_][a-zA-Z_0-9]*) +(.+)$", sLine.strip())
            if m:
                dDEF["{"+m.group(1)+"}"] = m.group(2)
            else:
                print("Error in definition: ", end="")
                print(sLine.strip())
        elif sLine.startswith("TEST:"):

            lTest.append("{:<8}".format(i) + "  " + sLine[5:].strip())
        elif sLine.startswith("TODO:"):

            pass
        elif sLine.startswith(("OPTGROUP/", "OPTSOFTWARE:", "OPT/", "OPTLANG/", "OPTDEFAULTUILANG:", "OPTLABEL/", "OPTPRIORITY/")):

            lOpt.append(sLine)
        elif re.match("[  \t]*$", sLine):
            pass
        elif sLine.startswith("!!"):
            m = zBookmark.search(sLine)

            nExMk = len(m.group(0))
            if sLine[nExMk:].strip():
                printBookmark(nExMk-2, sLine[nExMk:].strip(), i)






















        elif sLine.startswith(("    ", "\t")):

            lRuleLine[len(lRuleLine)-1][1] += " " + sLine.strip()
        else:

            lRuleLine.append([i, sLine.strip()])

    # generating options files
    print("  parsing options...")
    try:
        dOptions, dOptPriority = prepareOptions(lOpt)
    except:
................................................................................
                        lParagraphRules.append(aRule)
                        lParagraphRulesJS.append(jsconv.pyRuleToJS(aRule, dJSREGEXES, sWORDLIMITLEFT))
                    else:
                        lSentenceRules.append(aRule)
                        lSentenceRulesJS.append(jsconv.pyRuleToJS(aRule, dJSREGEXES, sWORDLIMITLEFT))

    # creating file with all functions callable by rules
    print("  creating callables...")
    sPyCallables = "# generated code, do not edit\n"
    sJSCallables = "// generated code, do not edit\nconst oEvalFunc = {\n"
    for sFuncName, sReturn in lFUNCTIONS:
        cType = sFuncName[0:1]
        if cType == "c": # condition
            sParams = "s, sx, m, dDA, sCountry, bCondMemo"
        elif cType == "m": # message

            sParams = "s, m"
        elif cType == "s": # suggestion
            sParams = "s, m"
        elif cType == "p": # preprocessor
            sParams = "s, m"
        elif cType == "d": # disambiguator
            sParams = "s, m, dDA"
        else:
            print("# Unknown function type in [" + sFuncName + "]")
            continue

        sPyCallables += "def {} ({}):\n".format(sFuncName, sParams)
        sPyCallables += "    return " + sReturn + "\n"

        sJSCallables += "    {}: function ({})".format(sFuncName, sParams) + " {\n"
        sJSCallables += "        return " + jsconv.py2js(sReturn) + ";\n"
        sJSCallables += "    },\n"
    sJSCallables += "}\n"

    displayStats(lParagraphRules, lSentenceRules)

    print("Unnamed rules: " + str(nRULEWITHOUTNAME))

    d = { "callables": sPyCallables,
          "callablesJS": sJSCallables,
          "gctests": sGCTests,
          "gctestsJS": sGCTestsJS,
          "paragraph_rules": mergeRulesByOption(lParagraphRules),
          "sentence_rules": mergeRulesByOption(lSentenceRules),
          "paragraph_rules_JS": jsconv.writeRulesToJSArray(mergeRulesByOption(lParagraphRulesJS)),
          "sentence_rules_JS": jsconv.writeRulesToJSArray(mergeRulesByOption(lSentenceRulesJS)) }
    d.update(dOptions)





    return d
>
>
>






>














>
>
>
>
>
>
>
>
>
>
>
>
>

>










|
|

|








|
|
|




|
|
|
|
|
|







 







>













<


>
>
>
>
>
>
>
>
>






|







 







|







 







|






|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



<
<









|
|
<
<


|







|







 







>


|
<
<
<
|

<
<
<
<
<
>
|
>

<
<


<
<
<

<
<
<
<
>
>
>
>
>
>
>
|
>



<
<

|
|







<
<

|
|







|
|
>
|
|

<
<
<






>


>
|
|




>







 







|







 







>







 







<
<



|
|



>



>

<
<
<
<
<

>







>


>


>

<
<

|
>


|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
|

>







 







|
|
|

<
|
|
<
>

|

|

|
|



>


>



<





|
|
|
|
|
|
|
|
|

>
>
>
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
...
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
...
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274


275
276
277
278
279
280
281
282
283
284
285


286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
...
308
309
310
311
312
313
314
315
316
317
318



319
320





321
322
323
324


325
326



327




328
329
330
331
332
333
334
335
336
337
338
339


340
341
342
343
344
345
346
347
348
349


350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365



366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
...
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
...
459
460
461
462
463
464
465


466
467
468
469
470
471
472
473
474
475
476
477
478
479





480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496


497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
...
561
562
563
564
565
566
567
568
569
570
571

572
573

574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591

592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
"""
Grammalecte: compile rules
"""

import re
import traceback
import json

import compile_rules_js_convert as jsconv
import compile_rules_graph as crg


dDEF = {}
lFUNCTIONS = []

aRULESET = set()     # set of rule-ids to check if there is several rules with the same id
nRULEWITHOUTNAME = 0

dJSREGEXES = {}

sWORDLIMITLEFT  = r"(?<![\w.,–-])"   # r"(?<![-.,—])\b"  seems slower
sWORDLIMITRIGHT = r"(?![\w–-])"      # r"\b(?!-—)"       seems slower


def _rgb (r, g, b):
    return (r & 255) << 16 | (g & 255) << 8 | (b & 255)


def getRGB (sHex):
    if sHex:
        r = int(sHex[:2], 16)
        g = int(sHex[2:4], 16)
        b = int(sHex[4:], 16)
        return _rgb(r, g, b)
    return _rgb(0, 0, 0)


def prepareFunction (s):
    "convert simple rule syntax to a string of Python code"
    s = s.replace("__also__", "bCondMemo")
    s = s.replace("__else__", "not bCondMemo")
    s = re.sub(r"isStart *\(\)", 'before("^ *$|, *$")', s)
    s = re.sub(r"isRealStart *\(\)", 'before("^ *$")', s)
    s = re.sub(r"isStart0 *\(\)", 'before0("^ *$|, *$")', s)
    s = re.sub(r"isRealStart0 *\(\)", 'before0("^ *$")', s)
    s = re.sub(r"isEnd *\(\)", 'after("^ *$|^,")', s)
    s = re.sub(r"isRealEnd *\(\)", 'after("^ *$")', s)
    s = re.sub(r"isEnd0 *\(\)", 'after0("^ *$|^,")', s)
    s = re.sub(r"isRealEnd0 *\(\)", 'after0("^ *$")', s)
    s = re.sub(r"(select|exclude)[(][\\](\d+)", '\\1(dTokenPos, m.start(\\2), m.group(\\2)', s)
    s = re.sub(r"define[(][\\](\d+)", 'define(dTokenPos, m.start(\\1)', s)
    s = re.sub(r"(morph|morphex|displayInfo)[(][\\](\d+)", '\\1((m.start(\\2), m.group(\\2))', s)
    s = re.sub(r"(morph|morphex|displayInfo)[(]", '\\1(dTokenPos, ', s)
    s = re.sub(r"(sugg\w+|switch\w+)\(@", '\\1(m.group(i[4])', s)
    s = re.sub(r"word\(\s*1\b", 'nextword1(s, m.end()', s)                                  # word(1)
    s = re.sub(r"word\(\s*-1\b", 'prevword1(s, m.start()', s)                               # word(-1)
    s = re.sub(r"word\(\s*(\d)", 'nextword(s, m.end(), \\1', s)                             # word(n)
    s = re.sub(r"word\(\s*-(\d)", 'prevword(s, m.start(), \\1', s)                          # word(-n)
    s = re.sub(r"before\(\s*", 'look(s[:m.start()], ', s)                                   # before(s)
    s = re.sub(r"after\(\s*", 'look(s[m.end():], ', s)                                      # after(s)
    s = re.sub(r"textarea\(\s*", 'look(s, ', s)                                             # textarea(s)
    s = re.sub(r"before_chk1\(\s*", 'look_chk1(dTokenPos, s[:m.start()], 0, ', s)           # before_chk1(s)
    s = re.sub(r"after_chk1\(\s*", 'look_chk1(dTokenPos, s[m.end():], m.end(), ', s)        # after_chk1(s)
    s = re.sub(r"textarea_chk1\(\s*", 'look_chk1(dTokenPos, s, 0, ', s)                     # textarea_chk1(s)
    s = re.sub(r"/0", 'sx[m.start():m.end()]', s)                                           # /0
    s = re.sub(r"before0\(\s*", 'look(sx[:m.start()], ', s)                                 # before0(s)
    s = re.sub(r"after0\(\s*", 'look(sx[m.end():], ', s)                                    # after0(s)
    s = re.sub(r"textarea0\(\s*", 'look(sx, ', s)                                           # textarea0(s)
    s = re.sub(r"before0_chk1\(\s*", 'look_chk1(dTokenPos, sx[:m.start()], 0, ', s)         # before0_chk1(s)
    s = re.sub(r"after0_chk1\(\s*", 'look_chk1(dTokenPos, sx[m.end():], m.end(), ', s)      # after0_chk1(s)
    s = re.sub(r"textarea0_chk1\(\s*", 'look_chk1(dTokenPos, sx, 0, ', s)                   # textarea0_chk1(s)
    s = re.sub(r"isEndOfNG\(\s*\)", 'isEndOfNG(dTokenPos, s[m.end():], m.end())', s)        # isEndOfNG(s)
    s = re.sub(r"isNextNotCOD\(\s*\)", 'isNextNotCOD(dTokenPos, s[m.end():], m.end())', s)  # isNextNotCOD(s)
    s = re.sub(r"isNextVerb\(\s*\)", 'isNextVerb(dTokenPos, s[m.end():], m.end())', s)      # isNextVerb(s)
    s = re.sub(r"\bspell *[(]", '_oSpellChecker.isValid(', s)
    s = re.sub(r"[\\](\d+)", 'm.group(\\1)', s)
    return s


def uppercase (s, sLang):
    "(flag i is not enough): converts regex to uppercase regex: 'foo' becomes '[Ff][Oo][Oo]', but 'Bar' becomes 'B[Aa][Rr]'."
................................................................................
            nState = 4
        elif nState == 4:
            nState = 0
    return sUp


def countGroupInRegex (sRegex):
    "returns the number of groups in <sRegex>"
    try:
        return re.compile(sRegex).groups
    except:
        traceback.print_exc()
        print(sRegex)
    return 0


def createRule (s, nIdLine, sLang, bParagraph, dOptPriority):
    "returns rule as list [option name, regex, bCaseInsensitive, identifier, list of actions]"
    global dJSREGEXES
    global nRULEWITHOUTNAME


    sLineId = str(nIdLine) + ("p" if bParagraph else "s")
    sRuleId = sLineId

    #### GRAPH CALL
    if s.startswith("@@@@"):
        if bParagraph:
            print("Error. Graph call can be made only after the first pass (sentence by sentence)")
            exit()
        return ["@@@@", s[4:], sLineId]

    #### OPTIONS
    sOption = False         # False or [a-z0-9]+ name
    nPriority = 4           # Default is 4, value must be between 0 and 9
    tGroups = None          # code for groups positioning (only useful for JavaScript)
    cCaseMode = 'i'         # i: case insensitive,  s: case sensitive,  u: uppercasing allowed
    cWordLimitLeft = '['    # [: word limit, <: no specific limit
    cWordLimitRight = ']'   # ]: word limit, >: no specific limit
    m = re.match("^__(?P<borders_and_case>[\\[<]\\w[\\]>])(?P<option>/[a-zA-Z0-9]+|)(?P<ruleid>\\(\\w+\\)|)(?P<priority>![0-9]|)__ *", s)
    if m:
        cWordLimitLeft = m.group('borders_and_case')[0]
        cCaseMode = m.group('borders_and_case')[1]
        cWordLimitRight = m.group('borders_and_case')[2]
        sOption = m.group('option')[1:]  if m.group('option')  else False
        if m.group('ruleid'):
            sRuleId =  m.group('ruleid')[1:-1]
................................................................................
    #### REGEX TRIGGER
    i = s.find(" <<-")
    if i == -1:
        print("# Error: no condition at line " + sLineId)
        return None
    sRegex = s[:i].strip()
    s = s[i+4:]

    # JS groups positioning codes
    m = re.search("@@\\S+", sRegex)
    if m:
        tGroups = jsconv.groupsPositioningCodeToList(sRegex[m.start()+2:])
        sRegex = sRegex[:m.start()].strip()
    # JS regex
    m = re.search("<js>.+</js>i?", sRegex)
................................................................................
        sRegex = sRegex.replace("(?i)", "")
        sRegex = uppercase(sRegex, sLang)
    else:
        print("# Unknown case mode [" + cCaseMode + "] at line " + sLineId)

    ## check regex
    try:
        re.compile(sRegex)
    except:
        print("# Regex error at line ", nIdLine)
        print(sRegex)
        traceback.print_exc()
        return None
    ## groups in non grouping parenthesis
    for x in re.finditer(r"\(\?:[^)]*\([\[\w -]", sRegex):
        print("# Warning: groups inside non grouping parenthesis in regex at line " + sLineId)

    #### PARSE ACTIONS
    lActions = []
    nAction = 1
    for sAction in s.split(" <<- "):
        t = createAction(sRuleId + "_" + str(nAction), sAction, nGroup)
................................................................................
        if t:
            lActions.append(t)
    if not lActions:
        return None

    return [sOption, sRegex, bCaseInsensitive, sLineId, sRuleId, nPriority, lActions, tGroups]


def checkReferenceNumbers (sText, sActionId, nToken):
    "check if token references in <sText> greater than <nToken> (debugging)"
    for x in re.finditer(r"\\(\d+)", sText):
        if int(x.group(1)) > nToken:
            print("# Error in token index at line " + sActionId + " ("+str(nToken)+" tokens only)")
            print(sText)


def checkIfThereIsCode (sText, sActionId):
    "check if there is code in <sText> (debugging)"
    if re.search("[.]\\w+[(]|sugg\\w+[(]|\\([0-9]|\\[[0-9]", sText):
        print("# Warning at line " + sActionId + ":  This message looks like code. Line should probably begin with =")
        print(sText)


def createAction (sIdAction, sAction, nGroup):
    "returns an action to perform as a tuple (condition, action type, action[, iGroup [, message, URL ]])"


    m = re.search(r"([-~=>])(\d*|)>>", sAction)
    if not m:
        print("# No action at line " + sIdAction)
        return None

    #### CONDITION
    sCondition = sAction[:m.start()].strip()
    if sCondition:
        sCondition = prepareFunction(sCondition)
        lFUNCTIONS.append(("_c_"+sIdAction, sCondition))
        checkReferenceNumbers(sCondition, sIdAction, nGroup)


        if ".match" in sCondition:
            print("# Error. JS compatibility. Don't use .match() in condition, use .search()")
        sCondition = "_c_"+sIdAction
    else:
        sCondition = None

    #### iGroup / positioning
    iGroup = int(m.group(2)) if m.group(2) else 0
    if iGroup > nGroup:
        print("# Selected group > group number in regex at line " + sIdAction)

    #### ACTION
    sAction = sAction[m.end():].strip()
    cAction = m.group(1)
    if cAction == "-":
        ## error
        iMsg = sAction.find(" # ")
        if iMsg == -1:
................................................................................
            sMsg = sAction[iMsg+3:].strip()
            sAction = sAction[:iMsg].strip()
            sURL = ""
            mURL = re.search("[|] *(https?://.*)", sMsg)
            if mURL:
                sURL = mURL.group(1).strip()
                sMsg = sMsg[:mURL.start(0)].strip()
            checkReferenceNumbers(sMsg, sIdAction, nGroup)
            if sMsg[0:1] == "=":
                sMsg = prepareFunction(sMsg[1:])
                lFUNCTIONS.append(("_m_"+sIdAction, sMsg))



                sMsg = "=_m_"+sIdAction
            else:





                checkIfThereIsCode(sMsg, sIdAction)

    checkReferenceNumbers(sAction, sIdAction, nGroup)
    if sAction[0:1] == "=" or cAction == "=":


        sAction = prepareFunction(sAction)
        sAction = sAction.replace("m.group(i[4])", "m.group("+str(iGroup)+")")



    else:




        checkIfThereIsCode(sAction, sIdAction)

    if cAction == ">":
        ## no action, break loop if condition is False
        return [sCondition, cAction, ""]

    if not sAction:
        print("# Error in action at line " + sIdAction + ":  This action is empty.")
        return None

    if cAction == "-":
        ## error detected --> suggestion


        if sAction[0:1] == "=":
            lFUNCTIONS.append(("_s_"+sIdAction, sAction[1:]))
            sAction = "=_s_"+sIdAction
        elif sAction.startswith('"') and sAction.endswith('"'):
            sAction = sAction[1:-1]
        if not sMsg:
            print("# Error in action at line " + sIdAction + ":  the message is empty.")
        return [sCondition, cAction, sAction, iGroup, sMsg, sURL]
    elif cAction == "~":
        ## text processor


        if sAction[0:1] == "=":
            lFUNCTIONS.append(("_p_"+sIdAction, sAction[1:]))
            sAction = "=_p_"+sIdAction
        elif sAction.startswith('"') and sAction.endswith('"'):
            sAction = sAction[1:-1]
        return [sCondition, cAction, sAction, iGroup]
    elif cAction == "=":
        ## disambiguator
        if sAction[0:1] == "=":
            sAction = sAction[1:]
        if "define" in sAction and not re.search(r"define\(dTokenPos, *m\.start.*, \[.*\] *\)", sAction):
            print("# Error in action at line " + sIdAction + ": second argument for define must be a list of strings")
            print(sAction)
        lFUNCTIONS.append(("_d_"+sIdAction, sAction))
        sAction = "_d_"+sIdAction
        return [sCondition, cAction, sAction]



    else:
        print("# Unknown action at line " + sIdAction)
        return None


def _calcRulesStats (lRules):
    "count rules and actions"
    d = {'=':0, '~': 0, '-': 0, '>': 0}
    for aRule in lRules:
        if aRule[0] != "@@@@":
            for aAction in aRule[6]:
                d[aAction[1]] = d[aAction[1]] + 1
    return (d, len(lRules))


def displayStats (lParagraphRules, lSentenceRules):
    "display rules numbers"
    print("  {:>18} {:>18} {:>18} {:>18}".format("DISAMBIGUATOR", "TEXT PROCESSOR", "GRAMMAR CHECKING", "REGEX"))
    d, nRule = _calcRulesStats(lParagraphRules)
    print("§ {:>10} actions {:>10} actions {:>10} actions  in {:>8} rules".format(d['='], d['~'], d['-'], nRule))
    d, nRule = _calcRulesStats(lSentenceRules)
    print("s {:>10} actions {:>10} actions {:>10} actions  in {:>8} rules".format(d['='], d['~'], d['-'], nRule))


................................................................................
            m = re.match("OPTGROUP/([a-z0-9]+):(.+)$", sLine)
            lStructOpt.append( (m.group(1), list(map(str.split, m.group(2).split(",")))) )
        elif sLine.startswith("OPTSOFTWARE:"):
            lOpt = [ [s, {}]  for s in sLine[12:].strip().split() ]  # don’t use tuples (s, {}), because unknown to JS
        elif sLine.startswith("OPT/"):
            m = re.match("OPT/([a-z0-9]+):(.+)$", sLine)
            for i, sOpt in enumerate(m.group(2).split()):
                lOpt[i][1][m.group(1)] = eval(sOpt)
        elif sLine.startswith("OPTPRIORITY/"):
            m = re.match("OPTPRIORITY/([a-z0-9]+): *([0-9])$", sLine)
            dOptPriority[m.group(1)] = int(m.group(2))
        elif sLine.startswith("OPTLANG/"):
            m = re.match("OPTLANG/([a-z][a-z](?:_[A-Z][A-Z]|)):(.+)$", sLine)
            sLang = m.group(1)[:2]
            dOptLabel[sLang] = { "__optiontitle__": m.group(2).strip() }
................................................................................
    print("  options defined for: " + ", ".join([ t[0] for t in lOpt ]))
    dOptions = { "lStructOpt": lStructOpt, "dOptLabel": dOptLabel, "sDefaultUILang": sDefaultUILang }
    dOptions.update({ "dOpt"+k: v  for k, v in lOpt })
    return dOptions, dOptPriority


def printBookmark (nLevel, sComment, nLine):
    "print bookmark within the rules file"
    print("  {:>6}:  {}".format(nLine, "  " * nLevel + sComment))


def make (spLang, sLang, bJavaScript):
    "compile rules, returns a dictionary of values"
    # for clarity purpose, don’t create any file here

................................................................................
        lRules = open(spLang + "/rules.grx", 'r', encoding="utf-8").readlines()
    except:
        print("Error. Rules file in project [" + sLang + "] not found.")
        exit()

    # removing comments, zeroing empty lines, creating definitions, storing tests, merging rule lines
    print("  parsing rules...")


    lRuleLine = []
    lTest = []
    lOpt = []
    bGraph = False
    lGraphRule = []

    for i, sLine in enumerate(lRules, 1):
        if sLine.startswith('#END'):
            # arbitrary end
            printBookmark(0, "BREAK BY #END", i)
            break
        elif sLine.startswith("#"):
            # comment
            pass





        elif sLine.startswith("DEF:"):
            # definition
            m = re.match("DEF: +([a-zA-Z_][a-zA-Z_0-9]*) +(.+)$", sLine.strip())
            if m:
                dDEF["{"+m.group(1)+"}"] = m.group(2)
            else:
                print("Error in definition: ", end="")
                print(sLine.strip())
        elif sLine.startswith("TEST:"):
            # test
            lTest.append("{:<8}".format(i) + "  " + sLine[5:].strip())
        elif sLine.startswith("TODO:"):
            # todo
            pass
        elif sLine.startswith(("OPTGROUP/", "OPTSOFTWARE:", "OPT/", "OPTLANG/", "OPTDEFAULTUILANG:", "OPTLABEL/", "OPTPRIORITY/")):
            # options
            lOpt.append(sLine)


        elif sLine.startswith("!!"):
            # bookmark
            m = re.match("!!+", sLine)
            nExMk = len(m.group(0))
            if sLine[nExMk:].strip():
                printBookmark(nExMk-2, sLine[nExMk:-3].strip(), i)
        # Graph rules
        elif sLine.startswith("@@@@GRAPH:"):
            # rules graph call
            m = re.match(r"@@@@GRAPH: *(\w+)", sLine.strip())
            if m:
                printBookmark(0, "GRAPH: " + m.group(1), i)
                lRuleLine.append([i, "@@@@"+m.group(1)])
                bGraph = True
            lGraphRule.append([i, sLine])
            bGraph = True
        elif sLine.startswith("@@@@END_GRAPH"):
            #lGraphRule.append([i, sLine])
            printBookmark(0, "ENDGRAPH", i)
            bGraph = False
        elif re.match("@@@@ *$", sLine):
            pass
        elif bGraph:
            lGraphRule.append([i, sLine])
        # Regex rules
        elif re.match("[  \t]*$", sLine):
            # empty line
            pass
        elif sLine.startswith(("    ", "\t")):
            # rule (continuation)
            lRuleLine[-1][1] += " " + sLine.strip()
        else:
            # new rule
            lRuleLine.append([i, sLine.strip()])

    # generating options files
    print("  parsing options...")
    try:
        dOptions, dOptPriority = prepareOptions(lOpt)
    except:
................................................................................
                        lParagraphRules.append(aRule)
                        lParagraphRulesJS.append(jsconv.pyRuleToJS(aRule, dJSREGEXES, sWORDLIMITLEFT))
                    else:
                        lSentenceRules.append(aRule)
                        lSentenceRulesJS.append(jsconv.pyRuleToJS(aRule, dJSREGEXES, sWORDLIMITLEFT))

    # creating file with all functions callable by rules
    print("  creating callables for regex rules...")
    sPyCallables = ""
    sJSCallables = ""
    for sFuncName, sReturn in lFUNCTIONS:

        if sFuncName.startswith("_c_"): # condition
            sParams = "s, sx, m, dTokenPos, sCountry, bCondMemo"

        elif sFuncName.startswith("_m_"): # message
            sParams = "s, m"
        elif sFuncName.startswith("_s_"): # suggestion
            sParams = "s, m"
        elif sFuncName.startswith("_p_"): # preprocessor
            sParams = "s, m"
        elif sFuncName.startswith("_d_"): # disambiguator
            sParams = "s, m, dTokenPos"
        else:
            print("# Unknown function type in [" + sFuncName + "]")
            continue
        # Python
        sPyCallables += "def {} ({}):\n".format(sFuncName, sParams)
        sPyCallables += "    return " + sReturn + "\n"
        # JavaScript
        sJSCallables += "    {}: function ({})".format(sFuncName, sParams) + " {\n"
        sJSCallables += "        return " + jsconv.py2js(sReturn) + ";\n"
        sJSCallables += "    },\n"


    displayStats(lParagraphRules, lSentenceRules)

    print("Unnamed rules: " + str(nRULEWITHOUTNAME))

    dVars = {   "callables": sPyCallables,
                "callablesJS": sJSCallables,
                "gctests": sGCTests,
                "gctestsJS": sGCTestsJS,
                "paragraph_rules": mergeRulesByOption(lParagraphRules),
                "sentence_rules": mergeRulesByOption(lSentenceRules),
                "paragraph_rules_JS": jsconv.writeRulesToJSArray(mergeRulesByOption(lParagraphRulesJS)),
                "sentence_rules_JS": jsconv.writeRulesToJSArray(mergeRulesByOption(lSentenceRulesJS)) }
    dVars.update(dOptions)

    # compile graph rules
    dVars2 = crg.make(lGraphRule, dDEF, sLang, dOptPriority, bJavaScript)
    dVars.update(dVars2)

    return dVars

Added compile_rules_graph.py version [f9b11563d7].



























































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
"""
Grammalecte: compile rules
Create a Direct Acyclic Rule Graphs (DARGs)
"""

import re
import traceback
import json

import darg
import compile_rules_js_convert as jsconv


dACTIONS = {}
dFUNCTIONS = {}
dFUNCNAME = {}


def createFunction (sType, sActionId, sCode, bStartWithEqual=False):
    "create a function (stored in <dFUNCTIONS>) and return function name"
    sCode = prepareFunction(sCode)
    if sType not in dFUNCNAME:
        dFUNCNAME[sType] = {}
    if sCode not in dFUNCNAME[sType]:
        dFUNCNAME[sType][sCode] = len(dFUNCNAME[sType])+1
    sFuncName = "_g_" + sType + "_" + str(dFUNCNAME[sType][sCode])
    dFUNCTIONS[sFuncName] = sCode
    return sFuncName  if not bStartWithEqual  else "="+sFuncName


def storeAction (sActionId, aAction):
    "store <aAction> in <dACTIONS> avoiding duplicates"
    nVar = 0
    while True:
        sActionName = sActionId + "_" + str(nVar)
        if sActionName not in dACTIONS:
            dACTIONS[sActionName] = aAction
            return sActionName
        elif aAction == dACTIONS[sActionName]:
            return sActionName
        nVar += 1


def prepareFunction (sCode):
    "convert simple rule syntax to a string of Python code"
    if sCode[0:1] == "=":
        sCode = sCode[1:]
    sCode = sCode.replace("__also__", "bCondMemo")
    sCode = sCode.replace("__else__", "not bCondMemo")
    sCode = sCode.replace("sContext", "_sAppContext")
    sCode = re.sub(r"(morph|morphVC|analyse|value|tag|displayInfo)[(]\\(\d+)", 'g_\\1(lToken[nTokenOffset+\\2]', sCode)
    sCode = re.sub(r"(morph|morphVC|analyse|value|tag|displayInfo)[(]\\-(\d+)", 'g_\\1(lToken[nLastToken-\\2+1]', sCode)
    sCode = re.sub(r"(select|exclude|define|define_from)[(][\\](\d+)", 'g_\\1(lToken[nTokenOffset+\\2]', sCode)
    sCode = re.sub(r"(select|exclude|define|define_from)[(][\\]-(\d+)", 'g_\\1(lToken[nLastToken-\\2+1]', sCode)
    sCode = re.sub(r"(tag_before|tag_after)[(][\\](\d+)", 'g_\\1(lToken[nTokenOffset+\\2], dTags', sCode)
    sCode = re.sub(r"(tag_before|tag_after)[(][\\]-(\d+)", 'g_\\1(lToken[nLastToken-\\2+1], dTags', sCode)
    sCode = re.sub(r"space_after[(][\\](\d+)", 'g_space_between_tokens(lToken[nTokenOffset+\\1], lToken[nTokenOffset+\\1+1]', sCode)
    sCode = re.sub(r"space_after[(][\\]-(\d+)", 'g_space_between_tokens(lToken[nLastToken-\\1+1], lToken[nLastToken-\\1+2]', sCode)
    sCode = re.sub(r"analyse_with_next[(][\\](\d+)", 'g_merged_analyse(lToken[nTokenOffset+\\1], lToken[nTokenOffset+\\1+1]', sCode)
    sCode = re.sub(r"analyse_with_next[(][\\]-(\d+)", 'g_merged_analyse(lToken[nLastToken-\\1+1], lToken[nLastToken-\\1+2]', sCode)
    sCode = re.sub(r"(morph|analyse|tag|value)\(>1", 'g_\\1(lToken[nLastToken+1]', sCode)                       # next token
    sCode = re.sub(r"(morph|analyse|tag|value)\(<1", 'g_\\1(lToken[nTokenOffset]', sCode)                       # previous token
    sCode = re.sub(r"(morph|analyse|tag|value)\(>(\d+)", 'g_\\1(g_token(lToken, nLastToken+\\2)', sCode)        # next token
    sCode = re.sub(r"(morph|analyse|tag|value)\(<(\d+)", 'g_\\1(g_token(lToken, nTokenOffset+1-\\2)', sCode)    # previous token
    sCode = re.sub(r"\bspell *[(]", '_oSpellChecker.isValid(', sCode)
    sCode = re.sub(r"\bbefore\(\s*", 'look(sSentence[:lToken[1+nTokenOffset]["nStart"]], ', sCode)          # before(sCode)
    sCode = re.sub(r"\bafter\(\s*", 'look(sSentence[lToken[nLastToken]["nEnd"]:], ', sCode)                 # after(sCode)
    sCode = re.sub(r"\bbefore0\(\s*", 'look(sSentence0[:lToken[1+nTokenOffset]["nStart"]], ', sCode)        # before0(sCode)
    sCode = re.sub(r"\bafter0\(\s*", 'look(sSentence[lToken[nLastToken]["nEnd"]:], ', sCode)                # after0(sCode)
    sCode = re.sub(r"analyseWord[(]", 'analyse(', sCode)
    sCode = re.sub(r"[\\](\d+)", 'lToken[nTokenOffset+\\1]["sValue"]', sCode)
    sCode = re.sub(r"[\\]-(\d+)", 'lToken[nLastToken-\\1+1]["sValue"]', sCode)
    return sCode


def genTokenLines (sTokenLine, dDef):
    "tokenize a string and return a list of lines of tokens"
    lToken = sTokenLine.split()
    lTokenLines = None
    for sToken in lToken:
        # optional token?
        bNullPossible = sToken.startswith("?") and sToken.endswith("¿")
        if bNullPossible:
            sToken = sToken[1:-1]
        # token with definition?
        if sToken.startswith("({") and sToken.endswith("})") and sToken[1:-1] in dDef:
            sToken = "(" + dDef[sToken[1:-1]] + ")"
        elif sToken.startswith("{") and sToken.endswith("}") and sToken in dDef:
            sToken = dDef[sToken]
        if ( (sToken.startswith("[") and sToken.endswith("]")) or (sToken.startswith("([") and sToken.endswith("])")) ):
            # multiple token
            bSelectedGroup = sToken.startswith("(") and sToken.endswith(")")
            if bSelectedGroup:
                sToken = sToken[1:-1]
            lNewToken = sToken[1:-1].split("|")
            if not lTokenLines:
                lTokenLines = [ ["("+s+")"]  for s  in lNewToken ]  if bSelectedGroup  else [ [s]  for s  in lNewToken ]
                if bNullPossible:
                    lTokenLines.extend([ []  for i  in range(len(lNewToken)+1) ])
            else:
                lNewTemp = []
                if bNullPossible:
                    for aRule in lTokenLines:
                        for sElem in lNewToken:
                            aNewRule = list(aRule)
                            aNewRule.append(sElem)
                            lNewTemp.append(aNewRule)
                else:
                    sElem1 = lNewToken.pop(0)
                    for aRule in lTokenLines:
                        for sElem in lNewToken:
                            aNewRule = list(aRule)
                            aNewRule.append("(" + sElem + ")"  if bSelectedGroup  else sElem)
                            lNewTemp.append(aNewRule)
                        aRule.append("(" + sElem1 + ")"  if bSelectedGroup  else sElem1)
                lTokenLines.extend(lNewTemp)
        else:
            # simple token
            if not lTokenLines:
                lTokenLines = [[sToken], []]  if bNullPossible  else [[sToken]]
            else:
                if bNullPossible:
                    lNewTemp = []
                    for aRule in lTokenLines:
                        lNew = list(aRule)
                        lNew.append(sToken)
                        lNewTemp.append(lNew)
                    lTokenLines.extend(lNewTemp)
                else:
                    for aRule in lTokenLines:
                        aRule.append(sToken)
    for aRule in lTokenLines:
        yield aRule


def createRule (iLine, sRuleName, sTokenLine, iActionBlock, sActions, nPriority, dOptPriority, dDef):
    "generator: create rule as list"
    # print(iLine, "//", sRuleName, "//", sTokenLine, "//", sActions, "//", nPriority)
    for lToken in genTokenLines(sTokenLine, dDef):
        # Calculate positions
        dPos = {}   # key: iGroup, value: iToken
        iGroup = 0
        #if iLine == 3971: # debug
        #    print(" ".join(lToken))
        for i, sToken in enumerate(lToken):
            if sToken.startswith("(") and sToken.endswith(")"):
                lToken[i] = sToken[1:-1]
                iGroup += 1
                dPos[iGroup] = i + 1    # we add 1, for we count tokens from 1 to n (not from 0)

        # Parse actions
        for iAction, sAction in enumerate(sActions.split(" <<- ")):
            sAction = sAction.strip()
            if sAction:
                sActionId = sRuleName + "__b" + str(iActionBlock) + "_a" + str(iAction)
                aAction = createAction(sActionId, sAction, nPriority, dOptPriority, len(lToken), dPos)
                if aAction:
                    sActionName = storeAction(sActionId, aAction)
                    lResult = list(lToken)
                    lResult.extend(["##"+str(iLine), sActionName])
                    #if iLine == 13341:
                    #    print("  ".join(lToken))
                    #    print(sActionId, aAction)
                    yield lResult
                else:
                    print(" # Error on action at line:", iLine)
                    print(sTokenLine, "\n", sActions)


def changeReferenceToken (sText, dPos):
    "change group reference in <sText> with values in <dPos>"
    for i in range(len(dPos), 0, -1):
        sText = sText.replace("\\"+str(i), "\\"+str(dPos[i]))
    return sText


def checkTokenNumbers (sText, sActionId, nToken):
    "check if token references in <sText> greater than <nToken> (debugging)"
    for x in re.finditer(r"\\(\d+)", sText):
        if int(x.group(1)) > nToken:
            print("# Error in token index at line " + sActionId + " ("+str(nToken)+" tokens only)")
            print(sText)


def checkIfThereIsCode (sText, sActionId):
    "check if there is code in <sText> (debugging)"
    if re.search("[.]\\w+[(]|sugg\\w+[(]|\\([0-9]|\\[[0-9]", sText):
        print("# Warning at line " + sActionId + ":  This message looks like code. Line should probably begin with =")
        print(sText)


def createAction (sActionId, sAction, nPriority, dOptPriority, nToken, dPos):
    "create action rule as a list"
    # Option
    sOption = False
    m = re.match("/(\\w+)/", sAction)
    if m:
        sOption = m.group(1)
        sAction = sAction[m.end():].strip()
    if nPriority == -1:
        nPriority = dOptPriority.get(sOption, 4)

    # valid action?
    m = re.search(r"(?P<action>[-~=/%>])(?P<start>-?\d+\.?|)(?P<end>:\.?-?\d+|)(?P<casing>:|)>>", sAction)
    if not m:
        print(" # Error. No action found at: ", sActionId)
        return None

    # Condition
    sCondition = sAction[:m.start()].strip()
    if sCondition:
        sCondition = changeReferenceToken(sCondition, dPos)
        sCondition = createFunction("cond", sActionId, sCondition)
    else:
        sCondition = ""

    # Case sensitivity
    bCaseSensitivity = False if m.group("casing") == ":" else True

    # Action
    cAction = m.group("action")
    sAction = sAction[m.end():].strip()
    sAction = changeReferenceToken(sAction, dPos)
    # target
    cStartLimit = "<"
    cEndLimit = ">"
    if not m.group("start"):
        iStartAction = 1
        iEndAction = 0
    else:
        if cAction != "-" and (m.group("start").endswith(".") or m.group("end").startswith(":.")):
            print(" # Error. Wrong selection on tokens.", sActionId)
            return None
        if m.group("start").endswith("."):
            cStartLimit = ">"
        iStartAction = int(m.group("start").rstrip("."))
        if not m.group("end"):
            iEndAction = iStartAction
        else:
            if m.group("end").startswith(":."):
                cEndLimit = "<"
            iEndAction = int(m.group("end").lstrip(":."))
    if dPos and m.group("start"):
        try:
            iStartAction = dPos.get(iStartAction, iStartAction)
            if iEndAction:
                iEndAction = dPos.get(iEndAction, iEndAction)
        except:
            print("# Error. Wrong groups in: " + sActionId)
            print("  iStartAction:", iStartAction, "iEndAction:", iEndAction)
            print(" ", dPos)
    if iStartAction < 0:
        iStartAction += 1
    if iEndAction < 0:
        iEndAction += 1

    if cAction == "-":
        ## error
        iMsg = sAction.find(" # ")
        if iMsg == -1:
            sMsg = "# Error. Error message not found."
            sURL = ""
            print(sMsg + " Action id: " + sActionId)
        else:
            sMsg = sAction[iMsg+3:].strip()
            sAction = sAction[:iMsg].strip()
            sURL = ""
            mURL = re.search("[|] *(https?://.*)", sMsg)
            if mURL:
                sURL = mURL.group(1).strip()
                sMsg = sMsg[:mURL.start(0)].strip()
            checkTokenNumbers(sMsg, sActionId, nToken)
            if sMsg[0:1] == "=":
                sMsg = createFunction("msg", sActionId, sMsg, True)
            else:
                checkIfThereIsCode(sMsg, sActionId)

    # checking consistancy
    checkTokenNumbers(sAction, sActionId, nToken)

    if cAction == ">":
        ## no action, break loop if condition is False
        return [sOption, sCondition, cAction, ""]

    if not sAction and cAction != "%":
        print("# Error in action at line " + sActionId + ":  This action is empty.")

    if sAction[0:1] != "=" and cAction != "=":
        checkIfThereIsCode(sAction, sActionId)

    if cAction == "-":
        ## error detected --> suggestion
        if sAction[0:1] == "=":
            sAction = createFunction("sugg", sActionId, sAction, True)
        elif sAction.startswith('"') and sAction.endswith('"'):
            sAction = sAction[1:-1]
        if not sMsg:
            print("# Error in action at line " + sActionId + ":  The message is empty.")
        return [sOption, sCondition, cAction, sAction, iStartAction, iEndAction, cStartLimit, cEndLimit, bCaseSensitivity, nPriority, sMsg, sURL]
    elif cAction == "~":
        ## text processor
        if sAction[0:1] == "=":
            sAction = createFunction("tp", sActionId, sAction, True)
        elif sAction.startswith('"') and sAction.endswith('"'):
            sAction = sAction[1:-1]
        return [sOption, sCondition, cAction, sAction, iStartAction, iEndAction, bCaseSensitivity]
    elif cAction == "%" or cAction == "/":
        ## tags
        return [sOption, sCondition, cAction, sAction, iStartAction, iEndAction]
    elif cAction == "=":
        ## disambiguator
        if "define(" in sAction and not re.search(r"define\(\\-?\d+ *, *\[.*\] *\)", sAction):
            print("# Error in action at line " + sActionId + ": second argument for <define> must be a list of strings")
        sAction = createFunction("da", sActionId, sAction)
        return [sOption, sCondition, cAction, sAction]
    else:
        print(" # Unknown action.", sActionId)
        return None


def make (lRule, dDef, sLang, dOptPriority, bJavaScript):
    "compile rules, returns a dictionary of values"
    # for clarity purpose, don’t create any file here

    # removing comments, zeroing empty lines, creating definitions, storing tests, merging rule lines
    print("  parsing rules...")
    lTokenLine = []
    sActions = ""
    nPriority = -1
    dAllGraph = {}
    sGraphName = ""
    iActionBlock = 0
    aRuleName = set()

    for i, sLine in lRule:
        sLine = sLine.rstrip()
        if "\t" in sLine:
            # tabulation not allowed
            print("Error. Tabulation at line: ", i)
            exit()
        elif sLine.startswith("@@@@GRAPH: "):
            # rules graph call
            m = re.match(r"@@@@GRAPH: *(\w+)", sLine.strip())
            if m:
                sGraphName = m.group(1)
                if sGraphName in dAllGraph:
                    print("Error at line " + i + ". Graph name <" + sGraphName + "> already exists.")
                    exit()
                dAllGraph[sGraphName] = []
            else:
                print("Error. Graph name not found at line", i)
                exit()
        elif sLine.startswith("__") and sLine.endswith("__"):
            # new rule group
            m = re.match("__(\\w+)(!\\d|)__", sLine)
            if m:
                sRuleName = m.group(1)
                if sRuleName in aRuleName:
                    print("Error at line " + i + ". Rule name <" + sRuleName + "> already exists.")
                    exit()
                iActionBlock = 1
                nPriority = int(m.group(2)[1:]) if m.group(2)  else -1
            else:
                print("Syntax error in rule group: ", sLine, " -- line:", i)
                exit()
        elif re.search("^    +<<- ", sLine) or (sLine.startswith("        ") and not sLine.startswith("        ||")) \
                or re.search("^    +#", sLine) or re.search(r"[-~=>/%](?:-?\d\.?(?::\.?-?\d+|)|)>> ", sLine) :
            # actions
            sActions += " " + sLine.strip()
        elif re.match("[  ]*$", sLine):
            # empty line to end merging
            if not lTokenLine:
                continue
            if not sActions:
                print("Error. No action found at line:", i)
                exit()
            if not sGraphName:
                print("Error. All rules must belong to a named graph. Line: ", i)
                exit()
            for j, sTokenLine in lTokenLine:
                dAllGraph[sGraphName].append((j, sRuleName, sTokenLine, iActionBlock, sActions, nPriority))
            lTokenLine.clear()
            sActions = ""
            iActionBlock += 1
        elif sLine.startswith("    "):
            # tokens
            sLine = sLine.strip()
            if sLine.startswith("||"):
                iPrevLine, sPrevLine = lTokenLine[-1]
                lTokenLine[-1] = [iPrevLine, sPrevLine + " " + sLine[2:]]
            else:
                lTokenLine.append([i, sLine])
        else:
            print("Unknown line:")
            print(sLine)

    # processing rules
    print("  preparing rules...")
    for sGraphName, lRuleLine in dAllGraph.items():
        print("{:>8,} rules in {:<24} ".format(len(lRuleLine), "<"+sGraphName+">"), end="")
        lPreparedRule = []
        for i, sRuleGroup, sTokenLine, iActionBlock, sActions, nPriority in lRuleLine:
            for lRule in createRule(i, sRuleGroup, sTokenLine, iActionBlock, sActions, nPriority, dOptPriority, dDef):
                lPreparedRule.append(lRule)
        # Graph creation
        oDARG = darg.DARG(lPreparedRule, sLang)
        dAllGraph[sGraphName] = oDARG.createGraph()
        # Debugging
        if False:
            print("\nRULES:")
            for e in lPreparedRule:
                if e[-2] == "##2211":
                    print(e)
        if False:
            print("\nGRAPH:", sGraphName)
            for k, v in dAllGraph[sGraphName].items():
                print(k, "\t", v)

    # creating file with all functions callable by rules
    print("  creating callables for graph rules...")
    sPyCallables = ""
    sJSCallables = ""
    for sFuncName, sReturn in dFUNCTIONS.items():
        if sFuncName.startswith("_g_cond_"): # condition
            sParams = "lToken, nTokenOffset, nLastToken, sCountry, bCondMemo, dTags, sSentence, sSentence0"
        elif sFuncName.startswith("g_msg_"): # message
            sParams = "lToken, nTokenOffset, nLastToken"
        elif sFuncName.startswith("_g_sugg_"): # suggestion
            sParams = "lToken, nTokenOffset, nLastToken"
        elif sFuncName.startswith("_g_tp_"): # text preprocessor
            sParams = "lToken, nTokenOffset, nLastToken"
        elif sFuncName.startswith("_g_da_"): # disambiguator
            sParams = "lToken, nTokenOffset, nLastToken"
        else:
            print("# Unknown function type in [" + sFuncName + "]")
            continue
        # Python
        sPyCallables += "def {} ({}):\n".format(sFuncName, sParams)
        sPyCallables += "    return " + sReturn + "\n"
        # JavaScript
        sJSCallables += "    {}: function ({})".format(sFuncName, sParams) + " {\n"
        sJSCallables += "        return " + jsconv.py2js(sReturn) + ";\n"
        sJSCallables += "    },\n"

    # Debugging
    if False:
        print("\nActions:")
        for sActionName, aAction in dACTIONS.items():
            print(sActionName, aAction)
        print("\nFunctions:")
        print(sPyCallables)

    # Result
    return {
        "graph_callables": sPyCallables,
        "graph_callablesJS": sJSCallables,
        "rules_graphs": dAllGraph,
        "rules_graphsJS": str(dAllGraph).replace("True", "true").replace("False", "false"),
        "rules_actions": dACTIONS,
        "rules_actionsJS": str(dACTIONS).replace("True", "true").replace("False", "false")
    }

Modified compile_rules_js_convert.py from [5ad87f3f46] to [9c357794f2].


1

2
3
4
5
6
7
8
..
18
19
20
21
22
23
24

25
26
27
28
29
30
31
..
51
52
53
54
55
56
57


58
59
60
61
62
63
64
...
114
115
116
117
118
119
120

121



122
123
124
125
126
127
128
129
130
131
132
133
134

135
136

137
138
139
140
141
142
143
144
145
146
147





148
149
150
151
152

153
154
155
156

# Convert Python code to JavaScript code


import copy
import re
import json


def py2js (sCode):
................................................................................
    sCode = sCode.replace(" and ", " && ")
    sCode = sCode.replace(" or ", " || ")
    sCode = re.sub("\\bnot\\b", "!", sCode)
    sCode = re.sub("(.+) if (.+) else (.+)", "(\\2) ? \\1 : \\3", sCode)
    # boolean
    sCode = sCode.replace("False", "false")
    sCode = sCode.replace("True", "true")

    sCode = sCode.replace("bool", "Boolean")
    # methods
    sCode = sCode.replace(".__len__()", ".length")
    sCode = sCode.replace(".endswith", ".endsWith")
    sCode = sCode.replace(".find", ".indexOf")
    sCode = sCode.replace(".startswith", ".startsWith")
    sCode = sCode.replace(".lower", ".toLowerCase")
................................................................................
    sCode = re.sub('(look_chk1\\(dDA, sx?[][.a-z:()]*, [0-9a-z.()]+), "([^"]+)"', "\\1, /\\2/i", sCode)
    sCode = re.sub('m\\.group\\((\\d+)\\) +in +(a[a-zA-Z]+)', "\\2.has(m[\\1])", sCode)
    sCode = sCode.replace("(?<!-)", "")  # todo
    # slices
    sCode = sCode.replace("[:m.start()]", ".slice(0,m.index)")
    sCode = sCode.replace("[m.end():]", ".slice(m.end[0])")
    sCode = sCode.replace("[m.start():m.end()]", ".slice(m.index, m.end[0])")


    sCode = re.sub("\\[(-?\\d+):(-?\\d+)\\]", ".slice(\\1,\\2)", sCode)
    sCode = re.sub("\\[(-?\\d+):\\]", ".slice(\\1)", sCode)
    sCode = re.sub("\\[:(-?\\d+)\\]", ".slice(0,\\1)", sCode)
    # regex matches
    sCode = sCode.replace(".end()", ".end[0]")
    sCode = sCode.replace(".start()", ".index")
    sCode = sCode.replace("m.group()", "m[0]")
................................................................................
        sRegex = sRegex + "i"
    if not lNegLookBeforeRegex:
        lNegLookBeforeRegex = None
    return (sRegex, lNegLookBeforeRegex)


def pyRuleToJS (lRule, dJSREGEXES, sWORDLIMITLEFT):

    lRuleJS = copy.deepcopy(lRule)



    del lRule[-1] # tGroups positioning codes are useless for Python
    # error messages
    for aAction in lRuleJS[6]:
        if aAction[1] == "-":
            aAction[2] = aAction[2].replace(" ", " ") # nbsp --> nnbsp
            aAction[4] = aAction[4].replace("« ", "« ").replace(" »", " »").replace(" :", " :").replace(" :", " :")
    # js regexes
    lRuleJS[1], lNegLookBehindRegex = regex2js(dJSREGEXES.get(lRuleJS[3], lRuleJS[1]), sWORDLIMITLEFT)
    lRuleJS.append(lNegLookBehindRegex)
    return lRuleJS


def writeRulesToJSArray (lRules):

    sArray = "[\n"
    for sOption, aRuleGroup in lRules:

        sArray += '  ["' + sOption + '", [\n'  if sOption  else  "  [false, [\n"
        for sRegex, bCaseInsensitive, sLineId, sRuleId, nPriority, lActions, aGroups, aNegLookBehindRegex in aRuleGroup:
            sArray += '    [' + sRegex + ", "
            sArray += "true, " if bCaseInsensitive  else "false, "
            sArray += '"' + sLineId + '", '
            sArray += '"' + sRuleId + '", '
            sArray += str(nPriority) + ", "
            sArray += json.dumps(lActions, ensure_ascii=False) + ", "
            sArray += json.dumps(aGroups, ensure_ascii=False) + ", "
            sArray += json.dumps(aNegLookBehindRegex, ensure_ascii=False) + "],\n"
        sArray += "  ]],\n"





    sArray += "]"
    return sArray


def groupsPositioningCodeToList (sGroupsPositioningCode):

    if not sGroupsPositioningCode:
        return None
    return [ int(sCode)  if sCode.isdigit() or (sCode[0:1] == "-" and sCode[1:].isdigit())  else sCode \
             for sCode in sGroupsPositioningCode.split(",") ]
>
|
>







 







>







 







>
>







 







>

>
>
>













>


>
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
>





>




1
2
3
4
5
6
7
8
9
10
..
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
..
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
"""
Convert Python code and regexes to JavaScript code
"""

import copy
import re
import json


def py2js (sCode):
................................................................................
    sCode = sCode.replace(" and ", " && ")
    sCode = sCode.replace(" or ", " || ")
    sCode = re.sub("\\bnot\\b", "!", sCode)
    sCode = re.sub("(.+) if (.+) else (.+)", "(\\2) ? \\1 : \\3", sCode)
    # boolean
    sCode = sCode.replace("False", "false")
    sCode = sCode.replace("True", "true")
    sCode = sCode.replace("None", "null")
    sCode = sCode.replace("bool", "Boolean")
    # methods
    sCode = sCode.replace(".__len__()", ".length")
    sCode = sCode.replace(".endswith", ".endsWith")
    sCode = sCode.replace(".find", ".indexOf")
    sCode = sCode.replace(".startswith", ".startsWith")
    sCode = sCode.replace(".lower", ".toLowerCase")
................................................................................
    sCode = re.sub('(look_chk1\\(dDA, sx?[][.a-z:()]*, [0-9a-z.()]+), "([^"]+)"', "\\1, /\\2/i", sCode)
    sCode = re.sub('m\\.group\\((\\d+)\\) +in +(a[a-zA-Z]+)', "\\2.has(m[\\1])", sCode)
    sCode = sCode.replace("(?<!-)", "")  # todo
    # slices
    sCode = sCode.replace("[:m.start()]", ".slice(0,m.index)")
    sCode = sCode.replace("[m.end():]", ".slice(m.end[0])")
    sCode = sCode.replace("[m.start():m.end()]", ".slice(m.index, m.end[0])")
    sCode = sCode.replace('[lToken[nLastToken]["nEnd"]:]', '.slice(lToken[nLastToken]["nEnd"])')
    sCode = sCode.replace('[:lToken[1+nTokenOffset]["nStart"]]', '.slice(0,lToken[1+nTokenOffset]["nStart"])')
    sCode = re.sub("\\[(-?\\d+):(-?\\d+)\\]", ".slice(\\1,\\2)", sCode)
    sCode = re.sub("\\[(-?\\d+):\\]", ".slice(\\1)", sCode)
    sCode = re.sub("\\[:(-?\\d+)\\]", ".slice(0,\\1)", sCode)
    # regex matches
    sCode = sCode.replace(".end()", ".end[0]")
    sCode = sCode.replace(".start()", ".index")
    sCode = sCode.replace("m.group()", "m[0]")
................................................................................
        sRegex = sRegex + "i"
    if not lNegLookBeforeRegex:
        lNegLookBeforeRegex = None
    return (sRegex, lNegLookBeforeRegex)


def pyRuleToJS (lRule, dJSREGEXES, sWORDLIMITLEFT):
    "modify Python rules -> JS rules"
    lRuleJS = copy.deepcopy(lRule)
    # graph rules
    if lRuleJS[0] == "@@@@":
        return lRuleJS
    del lRule[-1] # tGroups positioning codes are useless for Python
    # error messages
    for aAction in lRuleJS[6]:
        if aAction[1] == "-":
            aAction[2] = aAction[2].replace(" ", " ") # nbsp --> nnbsp
            aAction[4] = aAction[4].replace("« ", "« ").replace(" »", " »").replace(" :", " :").replace(" :", " :")
    # js regexes
    lRuleJS[1], lNegLookBehindRegex = regex2js(dJSREGEXES.get(lRuleJS[3], lRuleJS[1]), sWORDLIMITLEFT)
    lRuleJS.append(lNegLookBehindRegex)
    return lRuleJS


def writeRulesToJSArray (lRules):
    "create rules as a string of arrays (to be bundled in a JSON string)"
    sArray = "[\n"
    for sOption, aRuleGroup in lRules:
        if sOption != "@@@@":
            sArray += '  ["' + sOption + '", [\n'  if sOption  else  "  [false, [\n"
            for sRegex, bCaseInsensitive, sLineId, sRuleId, nPriority, lActions, aGroups, aNegLookBehindRegex in aRuleGroup:
                sArray += '    [' + sRegex + ", "
                sArray += "true, " if bCaseInsensitive  else "false, "
                sArray += '"' + sLineId + '", '
                sArray += '"' + sRuleId + '", '
                sArray += str(nPriority) + ", "
                sArray += json.dumps(lActions, ensure_ascii=False) + ", "
                sArray += json.dumps(aGroups, ensure_ascii=False) + ", "
                sArray += json.dumps(aNegLookBehindRegex, ensure_ascii=False) + "],\n"
            sArray += "  ]],\n"
        else:
            sArray += '  ["' + sOption + '", [\n'
            for sGraphName, sLineId in aRuleGroup:
                sArray += '    ["' + sGraphName + '", "' + sLineId + '"],\n'
            sArray += "  ]],\n"
    sArray += "]"
    return sArray


def groupsPositioningCodeToList (sGroupsPositioningCode):
    "convert <sGroupsPositioningCode> to a list of codes (numbers or strings)"
    if not sGroupsPositioningCode:
        return None
    return [ int(sCode)  if sCode.isdigit() or (sCode[0:1] == "-" and sCode[1:].isdigit())  else sCode \
             for sCode in sGroupsPositioningCode.split(",") ]

Added darg.py version [0a2000eec8].











































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
#!python3

"""
RULE GRAPH BUILDER
"""

# by Olivier R.
# License: MPL 2

import re
import traceback



class DARG:
    """DIRECT ACYCLIC RULE GRAPH"""
    # This code is inspired from Steve Hanov’s DAWG, 2011. (http://stevehanov.ca/blog/index.php?id=115)

    def __init__ (self, lRule, sLangCode):
        print(" > DARG", end="")

        # Preparing DARG
        self.sLangCode = sLangCode
        self.nRule = len(lRule)
        self.aPreviousRule = []
        Node.resetNextId()
        self.oRoot = Node()
        self.lUncheckedNodes = []  # list of nodes that have not been checked for duplication.
        self.lMinimizedNodes = {}  # list of unique nodes that have been checked for duplication.
        self.nNode = 0
        self.nArc = 0

        # build
        lRule.sort()
        for aRule in lRule:
            self.insert(aRule)
        self.finish()
        self.countNodes()
        self.countArcs()
        self.displayInfo()

    # BUILD DARG
    def insert (self, aRule):
        "insert a new rule (tokens must be inserted in order)"
        if aRule < self.aPreviousRule:
            exit("# Error: tokens must be inserted in order.")

        # find common prefix between word and previous word
        nCommonPrefix = 0
        for i in range(min(len(aRule), len(self.aPreviousRule))):
            if aRule[i] != self.aPreviousRule[i]:
                break
            nCommonPrefix += 1

        # Check the lUncheckedNodes for redundant nodes, proceeding from last
        # one down to the common prefix size. Then truncate the list at that point.
        self._minimize(nCommonPrefix)

        # add the suffix, starting from the correct node mid-way through the graph
        if len(self.lUncheckedNodes) == 0:
            oNode = self.oRoot
        else:
            oNode = self.lUncheckedNodes[-1][2]

        iToken = nCommonPrefix
        for sToken in aRule[nCommonPrefix:]:
            oNextNode = Node()
            oNode.dArcs[sToken] = oNextNode
            self.lUncheckedNodes.append((oNode, sToken, oNextNode))
            if iToken == (len(aRule) - 2):
                oNode.bFinal = True
            iToken += 1
            oNode = oNextNode
        oNode.bFinal = True
        self.aPreviousRule = aRule

    def finish (self):
        "minimize unchecked nodes"
        self._minimize(0)

    def _minimize (self, downTo):
        # proceed from the leaf up to a certain point
        for i in range( len(self.lUncheckedNodes)-1, downTo-1, -1 ):
            oNode, sToken, oChildNode = self.lUncheckedNodes[i]
            if oChildNode in self.lMinimizedNodes:
                # replace the child with the previously encountered one
                oNode.dArcs[sToken] = self.lMinimizedNodes[oChildNode]
            else:
                # add the state to the minimized nodes.
                self.lMinimizedNodes[oChildNode] = oChildNode
            self.lUncheckedNodes.pop()

    def countNodes (self):
        "count nodes within the whole graph"
        self.nNode = len(self.lMinimizedNodes)

    def countArcs (self):
        "count arcs within the whole graph"
        self.nArc = 0
        for oNode in self.lMinimizedNodes:
            self.nArc += len(oNode.dArcs)

    def displayInfo (self):
        "display informations about the rule graph"
        print(": {:>10,} rules,  {:>10,} nodes,  {:>10,} arcs".format(self.nRule, self.nNode, self.nArc))

    def createGraph (self):
        "create the graph as a dictionary"
        dGraph = { 0: self.oRoot.getNodeAsDict() }
        for oNode in self.lMinimizedNodes:
            sHashId = oNode.__hash__()
            if sHashId not in dGraph:
                dGraph[sHashId] = oNode.getNodeAsDict()
            else:
                print("Error. Double node… same id: ", sHashId)
                print(str(oNode.getNodeAsDict()))
        dGraph = self._rewriteKeysOfDARG(dGraph)
        self._sortActions(dGraph)
        self._checkRegexes(dGraph)
        return dGraph

    def _rewriteKeysOfDARG (self, dGraph):
        "keys of DARG are long numbers (hashes): this function replace these hashes with smaller numbers (to reduce storing size)"
        # create translation dictionary
        dKeyTrans = {}
        for i, nKey in enumerate(dGraph):
            dKeyTrans[nKey] = i
        # replace keys
        dNewGraph = {}
        for nKey, dVal in dGraph.items():
            dNewGraph[dKeyTrans[nKey]] = dVal
        for nKey, dVal in dGraph.items():
            for sArc, val in dVal.items():
                if type(val) is int:
                    dVal[sArc] = dKeyTrans[val]
                else:
                    for sArc, nKey in val.items():
                        val[sArc] = dKeyTrans[nKey]
        return dNewGraph

    def _sortActions (self, dGraph):
        "when a pattern is found, several actions may be launched, and it must be performed in a certain order"
        for nKey, dVal in dGraph.items():
            if "<rules>" in dVal:
                for sLineId, nKey in dVal["<rules>"].items():
                    # we change the dictionary of actions in a list of actions (values of dictionary all points to the final node)
                    if isinstance(dGraph[nKey], dict):
                        dGraph[nKey] = sorted(dGraph[nKey].keys())

    def _checkRegexes (self, dGraph):
        "check validity of regexes"
        aRegex = set()
        for nKey, dVal in dGraph.items():
            if "<re_value>" in dVal:
                for sRegex in dVal["<re_value>"]:
                    if sRegex not in aRegex:
                        self._checkRegex(sRegex)
                        aRegex.add(sRegex)
            if "<re_morph>" in dVal:
                for sRegex in dVal["<re_morph>"]:
                    if sRegex not in aRegex:
                        self._checkRegex(sRegex)
                        aRegex.add(sRegex)
        aRegex.clear()

    def _checkRegex (self, sRegex):
        #print(sRegex)
        if "¬" in sRegex:
            sPattern, sNegPattern = sRegex.split("¬")
            try:
                if not sNegPattern:
                    print("# Warning! Empty negpattern:", sRegex)
                re.compile(sPattern)
                if sNegPattern != "*":
                    re.compile(sNegPattern)
            except:
                print("# Error. Wrong regex:", sRegex)
                exit()
        else:
            try:
                if not sRegex:
                    print("# Warning! Empty pattern:", sRegex)
                re.compile(sRegex)
            except:
                print("# Error. Wrong regex:", sRegex)
                exit()


class Node:
    """Node of the rule graph"""

    NextId = 0

    def __init__ (self):
        self.i = Node.NextId
        Node.NextId += 1
        self.bFinal = False
        self.dArcs = {}          # key: arc value; value: a node

    @classmethod
    def resetNextId (cls):
        "reset to 0 the node counter"
        cls.NextId = 0

    def __str__ (self):
        # Caution! this function is used for hashing and comparison!
        cFinal = "1"  if self.bFinal  else "0"
        l = [cFinal]
        for (key, oNode) in self.dArcs.items():
            l.append(str(key))
            l.append(str(oNode.i))
        return "_".join(l)

    def __hash__ (self):
        # Used as a key in a python dictionary.
        return self.__str__().__hash__()

    def __eq__ (self, other):
        # Used as a key in a python dictionary.
        # Nodes are equivalent if they have identical arcs, and each identical arc leads to identical states.
        return self.__str__() == other.__str__()

    def getNodeAsDict (self):
        "returns the node as a dictionary structure"
        dNode = {}
        dReValue = {}
        dReMorph = {}
        dRule = {}
        dLemma = {}
        dMeta = {}
        dTag = {}
        for sArc, oNode in self.dArcs.items():
            if sArc.startswith("@") and len(sArc) > 1:
                dReMorph[sArc[1:]] = oNode.__hash__()
            elif sArc.startswith("~") and len(sArc) > 1:
                dReValue[sArc[1:]] = oNode.__hash__()
            elif sArc.startswith(">") and len(sArc) > 1:
                dLemma[sArc[1:]] = oNode.__hash__()
            elif sArc.startswith("*") and len(sArc) > 1:
                dMeta[sArc[1:]] = oNode.__hash__()
            elif sArc.startswith("/") and len(sArc) > 1:
                dTag[sArc[1:]] = oNode.__hash__()
            elif sArc.startswith("##"):
                dRule[sArc[1:]] = oNode.__hash__()
            else:
                dNode[sArc] = oNode.__hash__()
        if dReValue:
            dNode["<re_value>"] = dReValue
        if dReMorph:
            dNode["<re_morph>"] = dReMorph
        if dLemma:
            dNode["<lemmas>"] = dLemma
        if dTag:
            dNode["<tags>"] = dTag
        if dMeta:
            dNode["<meta>"] = dMeta
        if dRule:
            dNode["<rules>"] = dRule
        #if self.bFinal:
        #    dNode["<final>"] = 1
        return dNode

Modified gc_core/js/lang_core/gc_engine.js from [7ee1350cd7] to [f31744b125].

6
7
8
9
10
11
12
13
14
15

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
..
33
34
35
36
37
38
39
40
41

42

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178



179
180
181

182




183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248

249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266

267
268
269
270



271
272
273

274
275
276
277
278
279
280
281
282
283
...
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
...
357
358
359
360
361
362
363
364





















365
366
367
368

369
370
371



























372
373
374
375
376
377
378




























































































379


380
381
382














































































383
384
385
386





387
388

389
390
391
392
393
394
395
396





397


398
399
400
401
402
403




404
405
406
407


408
409
410
411
412
413
414







415
416

417









418


419


420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
































441
442



443


444
445
446
447






































































































448
449








450
451

452
453























454
455
456
457
458























































































459
460
461
462

































































463
464
465
466
467







468
469
470
471

472
473
474









































































475
476
477








478

479

480



















































































481
482
483
484
485
486
487
488
...
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
...
544
545
546
547
548
549
550
551
552
553
554
555
556
557









































































































































































































































558
559
560
561
562
563
564
565
566
567
568
569
570

571
572
573








574
575












576
577
578
579
580
581
582




























583
584
585
586
587
588
589
590

591
592
593
594
595
596
597
598
599
600
601
602
603

604
605
606

607
608
609
610
611
612










613
614
615
616
617
618
619
620
621



622
623



624
625
626
627
628
629
630
631
632

633


634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652


653

${string}
${regex}
${map}


if (typeof(require) !== 'undefined') {
    var helpers = require("resource://grammalecte/graphspell/helpers.js");
    var gc_options = require("resource://grammalecte/${lang}/gc_options.js");
    var gc_rules = require("resource://grammalecte/${lang}/gc_rules.js");

    var cregex = require("resource://grammalecte/${lang}/cregex.js");
    var text = require("resource://grammalecte/text.js");
    var echo = helpers.echo;
}
else if (typeof(console) !== "undefined") {
    var echo = function (o) { console.log(o); return true; };
}
else {
    var echo = function () { return true; }
}

function capitalizeArray (aArray) {
    // can’t map on user defined function??
    let aNew = [];
    for (let i = 0; i < aArray.length; i = i + 1) {
        aNew[i] = aArray[i].gl_toCapitalize();
    }
................................................................................
    return aNew;
}


// data
let _sAppContext = "";                                  // what software is running
let _dOptions = null;
let _aIgnoredRules = new Set();
let _oSpellChecker = null;

let _dAnalyses = new Map();                             // cache for data from dictionary



var gc_engine = {

    //// Informations

    lang: "${lang}",
    locales: ${loc},
    pkg: "${implname}",
    name: "${name}",
    version: "${version}",
    author: "${author}",

    //// Parsing

    parse: function (sText, sCountry="${country_default}", bDebug=false, bContext=false) {
        // analyses the paragraph sText and returns list of errors
        let dErrors;
        let errs;
        let sAlt = sText;
        let dDA = new Map();        // Disamnbiguator
        let dPriority = new Map();  // Key = position; value = priority
        let sNew = "";

        // parse paragraph
        try {
            [sNew, dErrors] = this._proofread(sText, sAlt, 0, true, dDA, dPriority, sCountry, bDebug, bContext);
            if (sNew) {
                sText = sNew;
            }
        }
        catch (e) {
            helpers.logerror(e);
        }

        // cleanup
        if (sText.includes(" ")) {
            sText = sText.replace(/ /g, ' '); // nbsp
        }
        if (sText.includes(" ")) {
            sText = sText.replace(/ /g, ' '); // snbsp
        }
        if (sText.includes("'")) {
            sText = sText.replace(/'/g, "’");
        }
        if (sText.includes("‑")) {
            sText = sText.replace(/‑/g, "-"); // nobreakdash
        }

        // parse sentence
        for (let [iStart, iEnd] of this._getSentenceBoundaries(sText)) {
            if (4 < (iEnd - iStart) < 2000) {
                dDA.clear();
                //helpers.echo(sText.slice(iStart, iEnd));
                try {
                    [, errs] = this._proofread(sText.slice(iStart, iEnd), sAlt.slice(iStart, iEnd), iStart, false, dDA, dPriority, sCountry, bDebug, bContext);
                    dErrors.gl_update(errs);
                }
                catch (e) {
                    helpers.logerror(e);
                }
            }
        }
        return Array.from(dErrors.values());
    },

    _zEndOfSentence: new RegExp ('([.?!:;…][ .?!… »”")]*|.$)', "g"),
    _zBeginOfParagraph: new RegExp ("^[-  –—.,;?!…]*", "ig"),
    _zEndOfParagraph: new RegExp ("[-  .,;?!…–—]*$", "ig"),

    _getSentenceBoundaries: function* (sText) {
        let mBeginOfSentence = this._zBeginOfParagraph.exec(sText);
        let iStart = this._zBeginOfParagraph.lastIndex;
        let m;
        while ((m = this._zEndOfSentence.exec(sText)) !== null) {
            yield [iStart, this._zEndOfSentence.lastIndex];
            iStart = this._zEndOfSentence.lastIndex;
        }
    },

    _proofread: function (s, sx, nOffset, bParagraph, dDA, dPriority, sCountry, bDebug, bContext) {
        let dErrs = new Map();
        let bChange = false;
        let bIdRule = option('idrule');
        let m;
        let bCondMemo;
        let nErrorStart;

        for (let [sOption, lRuleGroup] of this._getRules(bParagraph)) {
            if (!sOption || option(sOption)) {
                for (let [zRegex, bUppercase, sLineId, sRuleId, nPriority, lActions, lGroups, lNegLookBefore] of lRuleGroup) {
                    if (!_aIgnoredRules.has(sRuleId)) {
                        while ((m = zRegex.gl_exec2(s, lGroups, lNegLookBefore)) !== null) {
                            bCondMemo = null;
                            /*if (bDebug) {
                                helpers.echo(">>>> Rule # " + sLineId + " - Text: " + s + " opt: "+ sOption);
                            }*/
                            for (let [sFuncCond, cActionType, sWhat, ...eAct] of lActions) {
                            // action in lActions: [ condition, action type, replacement/suggestion/action[, iGroup[, message, URL]] ]
                                try {
                                    //helpers.echo(oEvalFunc[sFuncCond]);
                                    bCondMemo = (!sFuncCond || oEvalFunc[sFuncCond](s, sx, m, dDA, sCountry, bCondMemo));
                                    if (bCondMemo) {
                                        switch (cActionType) {
                                            case "-":
                                                // grammar error
                                                //helpers.echo("-> error detected in " + sLineId + "\nzRegex: " + zRegex.source);
                                                nErrorStart = nOffset + m.start[eAct[0]];
                                                if (!dErrs.has(nErrorStart) || nPriority > dPriority.get(nErrorStart)) {
                                                    dErrs.set(nErrorStart, this._createError(s, sx, sWhat, nOffset, m, eAct[0], sLineId, sRuleId, bUppercase, eAct[1], eAct[2], bIdRule, sOption, bContext));
                                                    dPriority.set(nErrorStart, nPriority);
                                                }
                                                break;
                                            case "~":
                                                // text processor
                                                //helpers.echo("-> text processor by " + sLineId + "\nzRegex: " + zRegex.source);
                                                s = this._rewrite(s, sWhat, eAct[0], m, bUppercase);
                                                bChange = true;
                                                if (bDebug) {
                                                    helpers.echo("~ " + s + "  -- " + m[eAct[0]] + "  # " + sLineId);
                                                }
                                                break;
                                            case "=":
                                                // disambiguation
                                                //helpers.echo("-> disambiguation by " + sLineId + "\nzRegex: " + zRegex.source);
                                                oEvalFunc[sWhat](s, m, dDA);
                                                if (bDebug) {
                                                    helpers.echo("= " + m[0] + "  # " + sLineId + "\nDA: " + dDA.gl_toString());
                                                }
                                                break;
                                            case ">":
                                                // we do nothing, this test is just a condition to apply all following actions
                                                break;
                                            default:
                                                helpers.echo("# error: unknown action at " + sLineId);
                                        }



                                    } else {
                                        if (cActionType == ">") {
                                            break;

                                        }




                                    }
                                }
                                catch (e) {
                                    helpers.echo(s);
                                    helpers.echo("# line id: " + sLineId + "\n# rule id: " + sRuleId);
                                    helpers.logerror(e);
                                }
                            }
                        }
                    }
                }
            }
        }
        if (bChange) {
            return [s, dErrs];
        }
        return [false, dErrs];
    },

    _createError: function (s, sx, sRepl, nOffset, m, iGroup, sLineId, sRuleId, bUppercase, sMsg, sURL, bIdRule, sOption, bContext) {
        let oErr = {};
        oErr["nStart"] = nOffset + m.start[iGroup];
        oErr["nEnd"] = nOffset + m.end[iGroup];
        oErr["sLineId"] = sLineId;
        oErr["sRuleId"] = sRuleId;
        oErr["sType"] = (sOption) ? sOption : "notype";
        // suggestions
        if (sRepl.slice(0,1) === "=") {
            let sugg = oEvalFunc[sRepl.slice(1)](s, m);
            if (sugg) {
                if (bUppercase && m[iGroup].slice(0,1).gl_isUpperCase()) {
                    oErr["aSuggestions"] = capitalizeArray(sugg.split("|"));
                } else {
                    oErr["aSuggestions"] = sugg.split("|");
                }
            } else {
                oErr["aSuggestions"] = [];
            }
        } else if (sRepl == "_") {
            oErr["aSuggestions"] = [];
        } else {
            if (bUppercase && m[iGroup].slice(0,1).gl_isUpperCase()) {
                oErr["aSuggestions"] = capitalizeArray(sRepl.gl_expand(m).split("|"));
            } else {
                oErr["aSuggestions"] = sRepl.gl_expand(m).split("|");
            }
        }
        // Message
        let sMessage = "";
        if (sMsg.slice(0,1) === "=") {
            sMessage = oEvalFunc[sMsg.slice(1)](s, m);
        } else {
            sMessage = sMsg.gl_expand(m);
        }
        if (bIdRule) {
            sMessage += " ##" + sLineId + " #" + sRuleId;
        }
        oErr["sMessage"] = sMessage;
        // URL
        oErr["URL"] = sURL || "";
        // Context
        if (bContext) {
            oErr["sUnderlined"] = sx.slice(m.start[iGroup], m.end[iGroup]);
            oErr["sBefore"] = sx.slice(Math.max(0, m.start[iGroup]-80), m.start[iGroup]);
            oErr["sAfter"] = sx.slice(m.end[iGroup], m.end[iGroup]+80);
        }

        return oErr;
    },

    _rewrite: function (s, sRepl, iGroup, m, bUppercase) {
        // text processor: write sRepl in s at iGroup position"
        let ln = m.end[iGroup] - m.start[iGroup];
        let sNew = "";
        if (sRepl === "*") {
            sNew = " ".repeat(ln);
        } else if (sRepl === ">" || sRepl === "_" || sRepl === "~") {
            sNew = sRepl + " ".repeat(ln-1);
        } else if (sRepl === "@") {
            sNew = "@".repeat(ln);
        } else if (sRepl.slice(0,1) === "=") {
            sNew = oEvalFunc[sRepl.slice(1)](s, m);
            sNew = sNew + " ".repeat(ln-sNew.length);
            if (bUppercase && m[iGroup].slice(0,1).gl_isUpperCase()) {
                sNew = sNew.gl_toCapitalize();

            }
        } else {
            sNew = sRepl.gl_expand(m);
            sNew = sNew + " ".repeat(ln-sNew.length);



        }
        //helpers.echo("\n"+s+"\nstart: "+m.start[iGroup]+" end:"+m.end[iGroup])
        return s.slice(0, m.start[iGroup]) + sNew + s.slice(m.end[iGroup]);

    },

    // Actions on rules

    ignoreRule: function (sRuleId) {
        _aIgnoredRules.add(sRuleId);
    },

    resetIgnoreRules: function () {
        _aIgnoredRules.clear();
................................................................................
    reactivateRule: function (sRuleId) {
        _aIgnoredRules.delete(sRuleId);
    },

    listRules: function* (sFilter=null) {
        // generator: returns tuple (sOption, sLineId, sRuleId)
        try {
            for (let [sOption, lRuleGroup] of this._getRules(true)) {
                for (let [,, sLineId, sRuleId,,] of lRuleGroup) {
                    if (!sFilter || sRuleId.test(sFilter)) {
                        yield [sOption, sLineId, sRuleId];
                    }
                }
            }
            for (let [sOption, lRuleGroup] of this._getRules(false)) {
                for (let [,, sLineId, sRuleId,,] of lRuleGroup) {
                    if (!sFilter || sRuleId.test(sFilter)) {
                        yield [sOption, sLineId, sRuleId];
                    }
                }
            }
        }
        catch (e) {
            helpers.logerror(e);
        }
    },

    _getRules: function (bParagraph) {
        if (!bParagraph) {
            return gc_rules.lSentenceRules;
        }
        return gc_rules.lParagraphRules;
    },

    //// Initialization

    load: function (sContext="JavaScript", sPath="") {
        try {
            if (typeof(require) !== 'undefined') {
                var spellchecker = require("resource://grammalecte/graphspell/spellchecker.js");
                _oSpellChecker = new spellchecker.SpellChecker("${lang}", "", "${dic_main_filename_js}", "${dic_extended_filename_js}", "${dic_community_filename_js}", "${dic_personal_filename_js}");
            } else {
                _oSpellChecker = new SpellChecker("${lang}", sPath, "${dic_main_filename_js}", "${dic_extended_filename_js}", "${dic_community_filename_js}", "${dic_personal_filename_js}");
            }
            _sAppContext = sContext;
            _dOptions = gc_options.getOptions(sContext).gl_shallowCopy();     // duplication necessary, to be able to reset to default
        }
        catch (e) {
            helpers.logerror(e);
        }
    },

    getSpellChecker: function () {
        return _oSpellChecker;
    },

    //// Options

    setOption: function (sOpt, bVal) {
        if (_dOptions.has(sOpt)) {
            _dOptions.set(sOpt, bVal);
        }
    },
................................................................................

    getDefaultOptions: function () {
        return gc_options.getOptions(_sAppContext).gl_shallowCopy();
    },

    resetOptions: function () {
        _dOptions = gc_options.getOptions(_sAppContext).gl_shallowCopy();
    }





















};


//////// Common functions


function option (sOpt) {
    // return true if option sOpt is active



























    return _dOptions.get(sOpt);
}

function displayInfo (dDA, aWord) {
    // for debugging: info of word
    if (!aWord) {
        helpers.echo("> nothing to find");




























































































        return true;


    }
    if (!_dAnalyses.has(aWord[1]) && !_storeMorphFromFSA(aWord[1])) {
        helpers.echo("> not in FSA");














































































        return true;
    }
    if (dDA.has(aWord[0])) {
        helpers.echo("DA: " + dDA.get(aWord[0]));





    }
    helpers.echo("FSA: " + _dAnalyses.get(aWord[1]));

    return true;
}

function _storeMorphFromFSA (sWord) {
    // retrieves morphologies list from _oSpellChecker -> _dAnalyses
    //helpers.echo("register: "+sWord + " " + _oSpellChecker.getMorph(sWord).toString())
    _dAnalyses.set(sWord, _oSpellChecker.getMorph(sWord));
    return !!_dAnalyses.get(sWord);





}



function morph (dDA, aWord, sPattern, bStrict=true, bNoWord=false) {
    // analyse a tuple (position, word), return true if sPattern in morphologies (disambiguation on)
    if (!aWord) {
        //helpers.echo("morph: noword, returns " + bNoWord);
        return bNoWord;




    }
    //helpers.echo("aWord: "+aWord.toString());
    if (!_dAnalyses.has(aWord[1]) && !_storeMorphFromFSA(aWord[1])) {
        return false;


    }
    let lMorph = dDA.has(aWord[0]) ? dDA.get(aWord[0]) : _dAnalyses.get(aWord[1]);
    //helpers.echo("lMorph: "+lMorph.toString());
    if (lMorph.length === 0) {
        return false;
    }
    //helpers.echo("***");







    if (bStrict) {
        return lMorph.every(s  =>  (s.search(sPattern) !== -1));

    }









    return lMorph.some(s  =>  (s.search(sPattern) !== -1));


}



function morphex (dDA, aWord, sPattern, sNegPattern, bNoWord=false) {
    // analyse a tuple (position, word), returns true if not sNegPattern in word morphologies and sPattern in word morphologies (disambiguation on)
    if (!aWord) {
        //helpers.echo("morph: noword, returns " + bNoWord);
        return bNoWord;
    }
    //helpers.echo("aWord: "+aWord.toString());
    if (!_dAnalyses.has(aWord[1]) && !_storeMorphFromFSA(aWord[1])) {
        return false;
    }
    let lMorph = dDA.has(aWord[0]) ? dDA.get(aWord[0]) : _dAnalyses.get(aWord[1]);
    //helpers.echo("lMorph: "+lMorph.toString());
    if (lMorph.length === 0) {
        return false;
    }
    //helpers.echo("***");
    // check negative condition
    if (lMorph.some(s  =>  (s.search(sNegPattern) !== -1))) {
        return false;
    }
































    // search sPattern
    return lMorph.some(s  =>  (s.search(sPattern) !== -1));



}



function analyse (sWord, sPattern, bStrict=true) {
    // analyse a word, return true if sPattern in morphologies (disambiguation off)
    if (!_dAnalyses.has(sWord) && !_storeMorphFromFSA(sWord)) {






































































































        return false;
    }








    if (bStrict) {
        return _dAnalyses.get(sWord).every(s  =>  (s.search(sPattern) !== -1));

    }
    return _dAnalyses.get(sWord).some(s  =>  (s.search(sPattern) !== -1));























}

function analysex (sWord, sPattern, sNegPattern) {
    // analyse a word, returns True if not sNegPattern in word morphologies and sPattern in word morphologies (disambiguation off)
    if (!_dAnalyses.has(sWord) && !_storeMorphFromFSA(sWord)) {























































































        return false;
    }
    // check negative condition
    if (_dAnalyses.get(sWord).some(s  =>  (s.search(sNegPattern) !== -1))) {

































































        return false;
    }
    // search sPattern
    return _dAnalyses.get(sWord).some(s  =>  (s.search(sPattern) !== -1));
}








function stem (sWord) {
    // returns a list of sWord's stems
    if (!sWord) {

        return [];
    }
    if (!_dAnalyses.has(sWord) && !_storeMorphFromFSA(sWord)) {









































































        return [];
    }
    return _dAnalyses.get(sWord).map( s => s.slice(1, s.indexOf(" ")) );








}























































































//// functions to get text outside pattern scope

// warning: check compile_rules.py to understand how it works

function nextword (s, iStart, n) {
    // get the nth word of the input string or empty string
    let z = new RegExp("^(?: +[a-zà-öA-Zø-ÿÀ-Ö0-9Ø-ßĀ-ʯfi-st%_-]+){" + (n-1).toString() + "} +([a-zà-öA-Zø-ÿÀ-Ö0-9Ø-ßĀ-ʯfi-st%_-]+)", "ig");
    let m = z.exec(s.slice(iStart));
................................................................................
    try {
        if (zNegPattern && zNegPattern.test(s)) {
            return false;
        }
        return zPattern.test(s);
    }
    catch (e) {
        helpers.logerror(e);
    }
    return false;
}

function look_chk1 (dDA, s, nOffset, zPattern, sPatternGroup1, sNegPatternGroup1=null) {
    // returns True if s has pattern zPattern and m.group(1) has pattern sPatternGroup1
    let m = zPattern.gl_exec2(s, null);
................................................................................
        return false;
    }
    try {
        let sWord = m[1];
        let nPos = m.start[1] + nOffset;
        if (sNegPatternGroup1) {
            return morphex(dDA, [nPos, sWord], sPatternGroup1, sNegPatternGroup1);
        } 
        return morph(dDA, [nPos, sWord], sPatternGroup1, false);
    }
    catch (e) {
        helpers.logerror(e);
        return false;
    }









































































































































































































































}


//////// Disambiguator

function select (dDA, nPos, sWord, sPattern, lDefault=null) {
    if (!sWord) {
        return true;
    }
    if (dDA.has(nPos)) {
        return true;
    }
    if (!_dAnalyses.has(sWord) && !_storeMorphFromFSA(sWord)) {

        return true;
    }
    if (_dAnalyses.get(sWord).length === 1) {








        return true;
    }












    let lSelect = _dAnalyses.get(sWord).filter( sMorph => sMorph.search(sPattern) !== -1 );
    if (lSelect.length > 0) {
        if (lSelect.length != _dAnalyses.get(sWord).length) {
            dDA.set(nPos, lSelect);
        }
    } else if (lDefault) {
        dDA.set(nPos, lDefaul);




























    }
    return true;
}

function exclude (dDA, nPos, sWord, sPattern, lDefault=null) {
    if (!sWord) {
        return true;
    }

    if (dDA.has(nPos)) {
        return true;
    }
    if (!_dAnalyses.has(sWord) && !_storeMorphFromFSA(sWord)) {
        return true;
    }
    if (_dAnalyses.get(sWord).length === 1) {
        return true;
    }
    let lSelect = _dAnalyses.get(sWord).filter( sMorph => sMorph.search(sPattern) === -1 );
    if (lSelect.length > 0) {
        if (lSelect.length != _dAnalyses.get(sWord).length) {
            dDA.set(nPos, lSelect);

        }
    } else if (lDefault) {
        dDA.set(nPos, lDefault);

    }
    return true;
}

function define (dDA, nPos, lMorph) {
    dDA.set(nPos, lMorph);










    return true;
}


//////// GRAMMAR CHECKER PLUGINS

${pluginsJS}





${callablesJS}






if (typeof(exports) !== 'undefined') {
    exports.lang = gc_engine.lang;
    exports.locales = gc_engine.locales;
    exports.pkg = gc_engine.pkg;
    exports.name = gc_engine.name;
    exports.version = gc_engine.version;
    exports.author = gc_engine.author;

    exports.parse = gc_engine.parse;


    exports._zEndOfSentence = gc_engine._zEndOfSentence;
    exports._zBeginOfParagraph = gc_engine._zBeginOfParagraph;
    exports._zEndOfParagraph = gc_engine._zEndOfParagraph;
    exports._getSentenceBoundaries = gc_engine._getSentenceBoundaries;
    exports._proofread = gc_engine._proofread;
    exports._createError = gc_engine._createError;
    exports._rewrite = gc_engine._rewrite;
    exports.ignoreRule = gc_engine.ignoreRule;
    exports.resetIgnoreRules = gc_engine.resetIgnoreRules;
    exports.reactivateRule = gc_engine.reactivateRule;
    exports.listRules = gc_engine.listRules;
    exports._getRules = gc_engine._getRules;
    exports.load = gc_engine.load;
    exports.getSpellChecker = gc_engine.getSpellChecker;
    exports.setOption = gc_engine.setOption;
    exports.setOptions = gc_engine.setOptions;
    exports.getOptions = gc_engine.getOptions;
    exports.getDefaultOptions = gc_engine.getDefaultOptions;
    exports.resetOptions = gc_engine.resetOptions;


}







<


>


<

<
<
|
<
<
<







 







<

>
|
>













|

|
<
<
<
<
<
<
<
<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>
>
>
|
<
<
>
|
>
>
>
>
|
<
|
<
<
|
|
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>
|


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>
|
<
<
<
>
>
>

<
<
>

<
<







 







|






|








|



<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



<
>

<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|

<
<
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
|
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
<
<
>
>
>
>
>
|
<
>
|
|
|
<
<
<
<
<
>
>
>
>
>
|
>
>
|
<
<
<
<
<
>
>
>
>
|
<
<
<
>
>
|
<
<
<
<
|
<
>
>
>
>
>
>
>
|
<
>
|
>
>
>
>
>
>
>
>
>
|
>
>
|
>
>
|
<
<
<
<
<
|
<
<
<
|
<
<
<
<
|
<
<
<
<
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
>
>
>
|
>
>
|
<
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

>
>
>
>
>
>
>
>
|
<
>
|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
<
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

<
<
|
>
>
>
>
>
>
>
|
<
<
<
>
|

<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
<
>
>
>
>
>
>
>
>
|
>
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|







 







|







 







|



|


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





|



|


|
>


<
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
|

|
|


|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




|
|
|
<
>
|
|
|
<


<
<
<
|
|
|
<
>


<
>




|
|
>
>
>
>
>
>
>
>
>
>









>
>
>


>
>
>









>
|
>
>



|
|
<
<




|
|
<





>
>

6
7
8
9
10
11
12

13
14
15
16
17

18


19



20
21
22
23
24
25
26
..
27
28
29
30
31
32
33

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53









54














































































































55
56
57
58


59
60
61
62
63
64
65

66


67
68
69
70

























































71
72
73
74















75
76



77
78
79
80


81
82


83
84
85
86
87
88
89
..
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118





























119
120
121
122
123
124
125
...
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165

166
167


168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197




198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293


294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373


374
375
376
377
378
379

380
381
382
383





384
385
386
387
388
389
390
391
392





393
394
395
396
397



398
399
400




401

402
403
404
405
406
407
408
409

410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427





428



429




430




431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464

465
466
467
468
469
470
471



472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584

585
586

587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611



612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700


701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767


768
769
770
771
772
773
774
775
776



777
778
779

780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854

855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
...
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
....
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276

1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340

1341
1342
1343
1344

1345
1346



1347
1348
1349

1350
1351
1352

1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404


1405
1406
1407
1408
1409
1410

1411
1412
1413
1414
1415
1416
1417
1418

${string}
${regex}
${map}


if (typeof(require) !== 'undefined') {

    var gc_options = require("resource://grammalecte/${lang}/gc_options.js");
    var gc_rules = require("resource://grammalecte/${lang}/gc_rules.js");
    var gc_rules_graph = require("resource://grammalecte/${lang}/gc_rules_graph.js");
    var cregex = require("resource://grammalecte/${lang}/cregex.js");
    var text = require("resource://grammalecte/text.js");

}







function capitalizeArray (aArray) {
    // can’t map on user defined function??
    let aNew = [];
    for (let i = 0; i < aArray.length; i = i + 1) {
        aNew[i] = aArray[i].gl_toCapitalize();
    }
................................................................................
    return aNew;
}


// data
let _sAppContext = "";                                  // what software is running
let _dOptions = null;

let _oSpellChecker = null;
let _oTokenizer = null;
let _aIgnoredRules = new Set();



var gc_engine = {

    //// Informations

    lang: "${lang}",
    locales: ${loc},
    pkg: "${implname}",
    name: "${name}",
    version: "${version}",
    author: "${author}",

    //// Initialization

    load: function (sContext="JavaScript", sPath="") {









        try {














































































































            if (typeof(require) !== 'undefined') {
                var spellchecker = require("resource://grammalecte/graphspell/spellchecker.js");
                _oSpellChecker = new spellchecker.SpellChecker("${lang}", "", "${dic_main_filename_js}", "${dic_extended_filename_js}", "${dic_community_filename_js}", "${dic_personal_filename_js}");
            } else {


                _oSpellChecker = new SpellChecker("${lang}", sPath, "${dic_main_filename_js}", "${dic_extended_filename_js}", "${dic_community_filename_js}", "${dic_personal_filename_js}");
            }
            _sAppContext = sContext;
            _dOptions = gc_options.getOptions(sContext).gl_shallowCopy();     // duplication necessary, to be able to reset to default
            _oTokenizer = _oSpellChecker.getTokenizer();
            _oSpellChecker.activateStorage();
        }

        catch (e) {


            console.error(e);
        }
    },


























































    getSpellChecker: function () {
        return _oSpellChecker;
    },
















    //// Rules




    getRules: function (bParagraph) {
        if (!bParagraph) {
            return gc_rules.lSentenceRules;
        }


        return gc_rules.lParagraphRules;
    },



    ignoreRule: function (sRuleId) {
        _aIgnoredRules.add(sRuleId);
    },

    resetIgnoreRules: function () {
        _aIgnoredRules.clear();
................................................................................
    reactivateRule: function (sRuleId) {
        _aIgnoredRules.delete(sRuleId);
    },

    listRules: function* (sFilter=null) {
        // generator: returns tuple (sOption, sLineId, sRuleId)
        try {
            for (let [sOption, lRuleGroup] of this.getRules(true)) {
                for (let [,, sLineId, sRuleId,,] of lRuleGroup) {
                    if (!sFilter || sRuleId.test(sFilter)) {
                        yield [sOption, sLineId, sRuleId];
                    }
                }
            }
            for (let [sOption, lRuleGroup] of this.getRules(false)) {
                for (let [,, sLineId, sRuleId,,] of lRuleGroup) {
                    if (!sFilter || sRuleId.test(sFilter)) {
                        yield [sOption, sLineId, sRuleId];
                    }
                }
            }
        }
        catch (e) {
            console.error(e);
        }
    },






























    //// Options

    setOption: function (sOpt, bVal) {
        if (_dOptions.has(sOpt)) {
            _dOptions.set(sOpt, bVal);
        }
    },
................................................................................

    getDefaultOptions: function () {
        return gc_options.getOptions(_sAppContext).gl_shallowCopy();
    },

    resetOptions: function () {
        _dOptions = gc_options.getOptions(_sAppContext).gl_shallowCopy();
    },

    //// Parsing

    parse: function (sText, sCountry="${country_default}", bDebug=false, dOptions=null, bContext=false) {
        let oText = new TextParser(sText);
        return oText.parse(sCountry, bDebug, dOptions, bContext);
    },

    _zEndOfSentence: new RegExp ('([.?!:;…][ .?!… »”")]*|.$)', "g"),
    _zBeginOfParagraph: new RegExp ("^[-  –—.,;?!…]*", "ig"),
    _zEndOfParagraph: new RegExp ("[-  .,;?!…–—]*$", "ig"),

    getSentenceBoundaries: function* (sText) {
        let mBeginOfSentence = this._zBeginOfParagraph.exec(sText);
        let iStart = this._zBeginOfParagraph.lastIndex;
        let m;
        while ((m = this._zEndOfSentence.exec(sText)) !== null) {
            yield [iStart, this._zEndOfSentence.lastIndex];
            iStart = this._zEndOfSentence.lastIndex;
        }
    }
};



class TextParser {



    constructor (sText) {
        this.sText = sText;
        this.sText0 = sText;
        this.sSentence = "";
        this.sSentence0 = "";
        this.nOffsetWithinParagraph = 0;
        this.lToken = [];
        this.dTokenPos = new Map();
        this.dTags = new Map();
        this.dError = new Map();
        this.dErrorPriority = new Map();  // Key = position; value = priority
    }

    asString () {
        let s = "===== TEXT =====\n"
        s += "sentence: " + this.sSentence0 + "\n";
        s += "now:      " + this.sSentence  + "\n";
        for (let dToken of this.lToken) {
            s += `#${dToken["i"]}\t${dToken["nStart"]}:${dToken["nEnd"]}\t${dToken["sValue"]}\t${dToken["sType"]}`;
            if (dToken.hasOwnProperty("lMorph")) {
                s += "\t" + dToken["lMorph"].toString();
            }
            if (dToken.hasOwnProperty("tags")) {
                s += "\t" + dToken["tags"].toString();
            }
            s += "\n";
        }
        return s;
    }





    parse (sCountry="${country_default}", bDebug=false, dOptions=null, bContext=false) {
        // analyses the paragraph sText and returns list of errors
        let dOpt = dOptions || _dOptions;
        let bShowRuleId = option('idrule');
        // parse paragraph
        try {
            this.parseText(this.sText, this.sText0, true, 0, sCountry, dOpt, bShowRuleId, bDebug, bContext);
        }
        catch (e) {
            console.error(e);
        }

        // cleanup
        if (this.sText.includes(" ")) {
            this.sText = this.sText.replace(/ /g, ' '); // nbsp
        }
        if (this.sText.includes(" ")) {
            this.sText = this.sText.replace(/ /g, ' '); // snbsp
        }
        if (this.sText.includes("'")) {
            this.sText = this.sText.replace(/'/g, "’");
        }
        if (this.sText.includes("‑")) {
            this.sText = this.sText.replace(/‑/g, "-"); // nobreakdash
        }

        // parse sentence
        for (let [iStart, iEnd] of gc_engine.getSentenceBoundaries(this.sText)) {
            try {
                this.sSentence = this.sText.slice(iStart, iEnd);
                this.sSentence0 = this.sText0.slice(iStart, iEnd);
                this.nOffsetWithinParagraph = iStart;
                this.lToken = Array.from(_oTokenizer.genTokens(this.sSentence, true));
                this.dTokenPos.clear();
                for (let dToken of this.lToken) {
                    if (dToken["sType"] != "INFO") {
                        this.dTokenPos.set(dToken["nStart"], dToken);
                    }
                }
                this.parseText(this.sSentence, this.sSentence0, false, iStart, sCountry, dOpt, bShowRuleId, bDebug, bContext);
            }
            catch (e) {
                console.error(e);
            }
        }
        return Array.from(this.dError.values());
    }

    parseText (sText, sText0, bParagraph, nOffset, sCountry, dOptions, bShowRuleId, bDebug, bContext) {
        let bChange = false;
        let m;

        for (let [sOption, lRuleGroup] of gc_engine.getRules(bParagraph)) {
            if (sOption == "@@@@") {
                // graph rules
                if (!bParagraph && bChange) {
                    this.update(sText, bDebug);
                    bChange = false;
                }
                for (let [sGraphName, sLineId] of lRuleGroup) {
                    if (!dOptions.has(sGraphName) || dOptions.get(sGraphName)) {
                        if (bDebug) {
                            console.log(">>>> GRAPH: " + sGraphName + " " + sLineId);
                        }
                        sText = this.parseGraph(gc_rules_graph.dAllGraph[sGraphName], sCountry, dOptions, bShowRuleId, bDebug, bContext);
                    }
                }
            }
            else if (!sOption || option(sOption)) {
                for (let [zRegex, bUppercase, sLineId, sRuleId, nPriority, lActions, lGroups, lNegLookBefore] of lRuleGroup) {
                    if (!_aIgnoredRules.has(sRuleId)) {
                        while ((m = zRegex.gl_exec2(sText, lGroups, lNegLookBefore)) !== null) {
                            let bCondMemo = null;
                            for (let [sFuncCond, cActionType, sWhat, ...eAct] of lActions) {
                                // action in lActions: [ condition, action type, replacement/suggestion/action[, iGroup[, message, URL]] ]
                                try {
                                    bCondMemo = (!sFuncCond || oEvalFunc[sFuncCond](sText, sText0, m, this.dTokenPos, sCountry, bCondMemo));
                                    if (bCondMemo) {
                                        switch (cActionType) {
                                            case "-":
                                                // grammar error
                                                //console.log("-> error detected in " + sLineId + "\nzRegex: " + zRegex.source);
                                                let nErrorStart = nOffset + m.start[eAct[0]];
                                                if (!this.dError.has(nErrorStart) || nPriority > this.dErrorPriority.get(nErrorStart)) {
                                                    this.dError.set(nErrorStart, this._createErrorFromRegex(sText, sText0, sWhat, nOffset, m, eAct[0], sLineId, sRuleId, bUppercase, eAct[1], eAct[2], bShowRuleId, sOption, bContext));
                                                    this.dErrorPriority.set(nErrorStart, nPriority);
                                                }
                                                break;
                                            case "~":
                                                // text processor
                                                //console.log("-> text processor by " + sLineId + "\nzRegex: " + zRegex.source);
                                                sText = this.rewriteText(sText, sWhat, eAct[0], m, bUppercase);
                                                bChange = true;
                                                if (bDebug) {
                                                    console.log("~ " + sText + "  -- " + m[eAct[0]] + "  # " + sLineId);
                                                }


                                                break;
                                            case "=":
                                                // disambiguation
                                                //console.log("-> disambiguation by " + sLineId + "\nzRegex: " + zRegex.source);
                                                oEvalFunc[sWhat](sText, m, this.dTokenPos);
                                                if (bDebug) {
                                                    console.log("= " + m[0] + "  # " + sLineId + "\nDA: " + dDA.gl_toString());
                                                }
                                                break;
                                            case ">":
                                                // we do nothing, this test is just a condition to apply all following actions
                                                break;
                                            default:
                                                console.log("# error: unknown action at " + sLineId);
                                        }
                                    } else {
                                        if (cActionType == ">") {
                                            break;
                                        }
                                    }
                                }
                                catch (e) {
                                    console.log(sText);
                                    console.log("# line id: " + sLineId + "\n# rule id: " + sRuleId);
                                    console.error(e);
                                }
                            }
                        }
                    }
                }
            }
        }
        if (bChange) {
            if (bParagraph) {
                this.sText = sText;
            } else {
                this.sSentence = sText;
            }
        }
    }

    update (sSentence, bDebug=false) {
        // update <sSentence> and retokenize
        this.sSentence = sSentence;
        let lNewToken = Array.from(_oTokenizer.genTokens(sSentence, true));
        for (let dToken of lNewToken) {
            if (this.dTokenPos.gl_get(dToken["nStart"], {}).hasOwnProperty("lMorph")) {
                dToken["lMorph"] = this.dTokenPos.get(dToken["nStart"])["lMorph"];
            }
            if (this.dTokenPos.gl_get(dToken["nStart"], {}).hasOwnProperty("tags")) {
                dToken["tags"] = this.dTokenPos.get(dToken["nStart"])["tags"];
            }
        }
        this.lToken = lNewToken;
        this.dTokenPos.clear();
        for (let dToken of this.lToken) {
            if (dToken["sType"] != "INFO") {
                this.dTokenPos.set(dToken["nStart"], dToken);
            }
        }
        if (bDebug) {
            console.log("UPDATE:");
            console.log(this.asString());
        }
    }

    * _getNextPointers (dToken, dGraph, dPointer, bDebug=false) {
        // generator: return nodes where <dToken> “values” match <dNode> arcs
        try {
            let dNode = dPointer["dNode"];
            let iNode1 = dPointer["iNode1"];
            let bTokenFound = false;
            // token value
            if (dNode.hasOwnProperty(dToken["sValue"])) {
                if (bDebug) {
                    console.log("  MATCH: " + dToken["sValue"]);
                }
                yield { "iNode1": iNode1, "dNode": dGraph[dNode[dToken["sValue"]]] };
                bTokenFound = true;
            }


            if (dToken["sValue"].slice(0,2).gl_isTitle()) { // we test only 2 first chars, to make valid words such as "Laissez-les", "Passe-partout".
                let sValue = dToken["sValue"].toLowerCase();
                if (dNode.hasOwnProperty(sValue)) {
                    if (bDebug) {
                        console.log("  MATCH: " + sValue);
                    }

                    yield { "iNode1": iNode1, "dNode": dGraph[dNode[sValue]] };
                    bTokenFound = true;
                }
            }





            else if (dToken["sValue"].gl_isUpperCase()) {
                let sValue = dToken["sValue"].toLowerCase();
                if (dNode.hasOwnProperty(sValue)) {
                    if (bDebug) {
                        console.log("  MATCH: " + sValue);
                    }
                    yield { "iNode1": iNode1, "dNode": dGraph[dNode[sValue]] };
                    bTokenFound = true;
                }





                sValue = dToken["sValue"].gl_toCapitalize();
                if (dNode.hasOwnProperty(sValue)) {
                    if (bDebug) {
                        console.log("  MATCH: " + sValue);
                    }



                    yield { "iNode1": iNode1, "dNode": dGraph[dNode[sValue]] };
                    bTokenFound = true;
                }




            }

            // regex value arcs
            if (dToken["sType"] != "INFO"  &&  dToken["sType"] != "PUNC"  &&  dToken["sType"] != "SIGN") {
                if (dNode.hasOwnProperty("<re_value>")) {
                    for (let sRegex in dNode["<re_value>"]) {
                        if (!sRegex.includes("¬")) {
                            // no anti-pattern
                            if (dToken["sValue"].search(sRegex) !== -1) {
                                if (bDebug) {

                                    console.log("  MATCH: ~" + sRegex);
                                }
                                yield { "iNode1": iNode1, "dNode": dGraph[dNode["<re_value>"][sRegex]] };
                                bTokenFound = true;
                            }
                        } else {
                            // there is an anti-pattern
                            let [sPattern, sNegPattern] = sRegex.split("¬", 1);
                            if (sNegPattern && dToken["sValue"].search(sNegPattern) !== -1) {
                                continue;
                            }
                            if (!sPattern || dToken["sValue"].search(sPattern) !== -1) {
                                if (bDebug) {
                                    console.log("  MATCH: ~" + sRegex);
                                }
                                yield { "iNode1": iNode1, "dNode": dGraph[dNode["<re_value>"][sRegex]] };
                                bTokenFound = true;
                            }





                        }



                    }




                }




            }
            // analysable tokens
            if (dToken["sType"].slice(0,4) == "WORD") {
                // token lemmas
                if (dNode.hasOwnProperty("<lemmas>")) {
                    for (let sLemma of _oSpellChecker.getLemma(dToken["sValue"])) {
                        if (dNode["<lemmas>"].hasOwnProperty(sLemma)) {
                            if (bDebug) {
                                console.log("  MATCH: >" + sLemma);
                            }
                            yield { "iNode1": iNode1, "dNode": dGraph[dNode["<lemmas>"][sLemma]] };
                            bTokenFound = true;
                        }
                    }
                }
                // regex morph arcs
                if (dNode.hasOwnProperty("<re_morph>")) {
                    let lMorph = (dToken.hasOwnProperty("lMorph")) ? dToken["lMorph"] : _oSpellChecker.getMorph(dToken["sValue"]);
                    for (let sRegex in dNode["<re_morph>"]) {
                        if (!sRegex.includes("¬")) {
                            // no anti-pattern
                            if (lMorph.some(sMorph  =>  (sMorph.search(sRegex) !== -1))) {
                                if (bDebug) {
                                    console.log("  MATCH: @" + sRegex);
                                }
                                yield { "iNode1": iNode1, "dNode": dGraph[dNode["<re_morph>"][sRegex]] };
                                bTokenFound = true;
                            }
                        } else {
                            // there is an anti-pattern
                            let [sPattern, sNegPattern] = sRegex.split("¬", 1);
                            if (sNegPattern == "*") {
                                // all morphologies must match with <sPattern>
                                if (sPattern) {

                                    if (lMorph.length > 0  &&  lMorph.every(sMorph  =>  (sMorph.search(sPattern) !== -1))) {
                                        if (bDebug) {
                                            console.log("  MATCH: @" + sRegex);
                                        }
                                        yield { "iNode1": iNode1, "dNode": dGraph[dNode["<re_morph>"][sRegex]] };
                                        bTokenFound = true;
                                    }



                                }
                            } else {
                                if (sNegPattern  &&  lMorph.some(sMorph  =>  (sMorph.search(sNegPattern) !== -1))) {
                                    continue;
                                }
                                if (!sPattern  ||  lMorph.some(sMorph  =>  (sMorph.search(sPattern) !== -1))) {
                                    if (bDebug) {
                                        console.log("  MATCH: @" + sRegex);
                                    }
                                    yield { "iNode1": iNode1, "dNode": dGraph[dNode["<re_morph>"][sRegex]] };
                                    bTokenFound = true;
                                }
                            }
                        }
                    }
                }
            }
            // token tags
            if (dToken.hasOwnProperty("tags") && dNode.hasOwnProperty("<tags>")) {
                for (let sTag in dToken["tags"]) {
                    if (dNode["<tags>"].hasOwnProperty(sTag)) {
                        if (bDebug) {
                            console.log("  MATCH: /" + sTag);
                        }
                        yield { "iNode1": iNode1, "dNode": dGraph[dNode["<tags>"][sTag]] };
                        bTokenFound = true;
                    }
                }
            }
            // meta arc (for token type)
            if (dNode.hasOwnProperty("<meta>")) {
                for (let sMeta in dNode["<meta>"]) {
                    // no regex here, we just search if <dNode["sType"]> exists within <sMeta>
                    if (sMeta == "*" || dToken["sType"] == sMeta) {
                        if (bDebug) {
                            console.log("  MATCH: *" + sMeta);
                        }
                        yield { "iNode1": iNode1, "dNode": dGraph[dNode["<meta>"][sMeta]] };
                        bTokenFound = true;
                    }
                    else if (sMeta.includes("¬")) {
                        if (!sMeta.includes(dToken["sType"])) {
                            if (bDebug) {
                                console.log("  MATCH: *" + sMeta);
                            }
                            yield { "iNode1": iNode1, "dNode": dGraph[dNode["<meta>"][sMeta]] };
                            bTokenFound = true;
                        }
                    }
                }
            }
            if (!bTokenFound  &&  dPointer.hasOwnProperty("bKeep")) {
                yield dPointer;
            }
            // JUMP
            // Warning! Recurssion!
            if (dNode.hasOwnProperty("<>")) {
                let dPointer2 = { "iNode1": iNode1, "dNode": dGraph[dNode["<>"]], "bKeep": true };
                yield* this._getNextPointers(dToken, dGraph, dPointer2, bDebug);
            }
        }
        catch (e) {
            console.error(e);
        }
    }

    parseGraph (dGraph, sCountry="${country_default}", dOptions=null, bShowRuleId=false, bDebug=false, bContext=false) {
        // parse graph with tokens from the text and execute actions encountered
        let lPointer = [];
        let bTagAndRewrite = false;
        try {
            for (let [iToken, dToken] of this.lToken.entries()) {
                if (bDebug) {
                    console.log("TOKEN: " + dToken["sValue"]);
                }
                // check arcs for each existing pointer
                let lNextPointer = [];
                for (let dPointer of lPointer) {
                    lNextPointer.push(...this._getNextPointers(dToken, dGraph, dPointer, bDebug));
                }
                lPointer = lNextPointer;
                // check arcs of first nodes
                lPointer.push(...this._getNextPointers(dToken, dGraph, { "iNode1": iToken, "dNode": dGraph[0] }, bDebug));
                // check if there is rules to check for each pointer
                for (let dPointer of lPointer) {
                    if (dPointer["dNode"].hasOwnProperty("<rules>")) {
                        let bChange = this._executeActions(dGraph, dPointer["dNode"]["<rules>"], dPointer["iNode1"]-1, iToken, dOptions, sCountry, bShowRuleId, bDebug, bContext);
                        if (bChange) {
                            bTagAndRewrite = true;
                        }
                    }
                }
            }
        } catch (e) {
            console.error(e);
        }
        if (bTagAndRewrite) {
            this.rewriteFromTags(bDebug);
        }
        if (bDebug) {
            console.log(this);
        }
        return this.sSentence;
    }

    _executeActions (dGraph, dNode, nTokenOffset, nLastToken, dOptions, sCountry, bShowRuleId, bDebug, bContext) {
        // execute actions found in the DARG
        let bChange = false;
        for (let [sLineId, nextNodeKey] of Object.entries(dNode)) {
            let bCondMemo = null;
            for (let sRuleId of dGraph[nextNodeKey]) {
                try {
                    if (bDebug) {

                        console.log("   >TRY: " + sRuleId);
                    }

                    let [sOption, sFuncCond, cActionType, sWhat, ...eAct] = gc_rules_graph.dRule[sRuleId];
                    // Suggestion    [ option, condition, "-", replacement/suggestion/action, iTokenStart, iTokenEnd, cStartLimit, cEndLimit, bCaseSvty, nPriority, sMessage, sURL ]
                    // TextProcessor [ option, condition, "~", replacement/suggestion/action, iTokenStart, iTokenEnd, bCaseSvty ]
                    // Disambiguator [ option, condition, "=", replacement/suggestion/action ]
                    // Tag           [ option, condition, "/", replacement/suggestion/action, iTokenStart, iTokenEnd ]
                    // Immunity      [ option, condition, "%", "",                            iTokenStart, iTokenEnd ]
                    // Test          [ option, condition, ">", "" ]
                    if (!sOption || dOptions.gl_get(sOption, false)) {
                        bCondMemo = !sFuncCond || oEvalFunc[sFuncCond](this.lToken, nTokenOffset, nLastToken, sCountry, bCondMemo, this.dTags, this.sSentence, this.sSentence0);
                        if (bCondMemo) {
                            if (cActionType == "-") {
                                // grammar error
                                let [iTokenStart, iTokenEnd, cStartLimit, cEndLimit, bCaseSvty, nPriority, sMessage, sURL] = eAct;
                                let nTokenErrorStart = (iTokenStart > 0) ? nTokenOffset + iTokenStart : nLastToken + iTokenStart;
                                if (!this.lToken[nTokenErrorStart].hasOwnProperty("bImmune")) {
                                    let nTokenErrorEnd = (iTokenEnd > 0) ? nTokenOffset + iTokenEnd : nLastToken + iTokenEnd;
                                    let nErrorStart = this.nOffsetWithinParagraph + ((cStartLimit == "<") ? this.lToken[nTokenErrorStart]["nStart"] : this.lToken[nTokenErrorStart]["nEnd"]);
                                    let nErrorEnd = this.nOffsetWithinParagraph + ((cEndLimit == ">") ? this.lToken[nTokenErrorEnd]["nEnd"] : this.lToken[nTokenErrorEnd]["nStart"]);
                                    if (!this.dError.has(nErrorStart) || nPriority > this.dErrorPriority.get(nErrorStart, -1)) {
                                        this.dError[nErrorStart] = this._createErrorFromTokens(sWhat, nTokenOffset, nLastToken, nTokenErrorStart, nErrorStart, nErrorEnd, sLineId, sRuleId, bCaseSvty, sMessage, sURL, bShowRuleId, sOption, bContext);
                                        this.dErrorPriority[nErrorStart] = nPriority;
                                        if (bDebug) {
                                            console.log(`    NEW_ERROR:  ${sRuleId}  ${sLineId}:  ${this.dError[nErrorStart]}`);
                                        }
                                    }



                                }
                            }
                            else if (cActionType == "~") {
                                // text processor
                                let nTokenStart = (eAct[0] > 0) ? nTokenOffset + eAct[0] : nLastToken + eAct[0];
                                let nTokenEnd = (eAct[1] > 0) ? nTokenOffset + eAct[1] : nLastToken + eAct[1];
                                this._tagAndPrepareTokenForRewriting(sWhat, nTokenStart, nTokenEnd, nTokenOffset, nLastToken, eAct[2], bDebug);
                                bChange = true;
                                if (bDebug) {
                                    console.log(`    TEXT_PROCESSOR:  ${sRuleId} ${sLineId}`);
                                    console.log(`      [${this.lToken[nTokenStart]["sValue"]}:${this.lToken[nTokenEnd]["sValue"]}]  > ${sWhat}`);
                                }
                            }
                            else if (cActionType == "=") {
                                // disambiguation
                                oEvalFunc[sWhat](this.lToken, nTokenOffset, nLastToken);
                                if (bDebug) {
                                    console.log(`    DISAMBIGUATOR:  ${sRuleId} ${sLineId} (${sWhat})  ${this.lToken[nTokenOffset+1]["sValue"]}:${this.lToken[nLastToken]["sValue"]}`);
                                }
                            }
                            else if (cActionType == ">") {
                                // we do nothing, this test is just a condition to apply all following actions
                                if (bDebug) {
                                    console.log(`    COND_OK:  ${sRuleId} ${sLineId}`);
                                }
                            }
                            else if (cActionType == "/") {
                                // Tag
                                let nTokenStart = (eAct[0] > 0) ? nTokenOffset + eAct[0] : nLastToken + eAct[0];
                                let nTokenEnd = (eAct[1] > 0) ? nTokenOffset + eAct[1] : nLastToken + eAct[1];
                                for (let i = nTokenStart; i <= nTokenEnd; i++) {
                                    if (this.lToken[i].hasOwnProperty("tags")) {
                                        this.lToken[i]["tags"].add(...sWhat.split("|"))
                                    } else {
                                        this.lToken[i]["tags"] = new Set(sWhat.split("|"));
                                    }
                                }
                                if (bDebug) {
                                    console.log(`    TAG:  ${sRuleId} ${sLineId}`);
                                    console.log(`      ${sWhat} > ${this.lToken[nTokenStart]["sValue"]} : ${this.lToken[nTokenEnd]["sValue"]}`);
                                }
                                if (!this.dTags.has(sWhat)) {
                                    this.dTags.set(sWhat, [nTokenStart, nTokenStart]);
                                } else {
                                    this.dTags.set(sWhat, [Math.min(nTokenStart, this.dTags.get(sWhat)[0]), Math.max(nTokenEnd, this.dTags.get(sWhat)[1])]);
                                }
                            }
                            else if (cActionType == "%") {
                                // immunity
                                if (bDebug) {
                                    console.log("    IMMUNITY:\n      " + _rules_graph.dRule[sRuleId]);
                                }
                                nTokenStart = (eAct[0] > 0) ? nTokenOffset + eAct[0] : nLastToken + eAct[0];
                                nTokenEnd = (eAct[1] > 0) ? nTokenOffset + eAct[1] : nLastToken + eAct[1];
                                if (nTokenEnd - nTokenStart == 0) {
                                    this.lToken[nTokenStart]["bImmune"] = true;
                                    let nErrorStart = this.nOffsetWithinParagraph + this.lToken[nTokenStart]["nStart"];
                                    if (this.dError.has(nErrorStart)) {
                                        this.dError.delete(nErrorStart);
                                    }
                                } else {
                                    for (let i = nTokenStart;  i <= nTokenEnd;  i++) {
                                        this.lToken[i]["bImmune"] = true;
                                        let nErrorStart = this.nOffsetWithinParagraph + this.lToken[i]["nStart"];
                                        if (this.dError.has(nErrorStart)) {
                                            this.dError.delete(nErrorStart);
                                        }
                                    }
                                }
                            } else {
                                console.log("# error: unknown action at " + sLineId);
                            }
                        }
                        else if (cActionType == ">") {
                            if (bDebug) {
                                console.log(`    COND_BREAK:  ${sRuleId} ${sLineId}`);
                            }
                            break;
                        }
                    }
                }
                catch (e) {
                    console.log("Error: ", sLineId, sRuleId, this.sSentence);
                    console.error(e);
                }
            }
        }
        return bChange;
    }



    _createErrorFromRegex (sText, sText0, sSugg, nOffset, m, iGroup, sLineId, sRuleId, bUppercase, sMsg, sURL, bShowRuleId, sOption, bContext) {
        let nStart = nOffset + m.start[iGroup];
        let nEnd = nOffset + m.end[iGroup];
        // suggestions
        let lSugg = [];
        if (sSugg.startsWith("=")) {
            sSugg = oEvalFunc[sSugg.slice(1)](sText, m);
            lSugg = (sSugg) ? sSugg.split("|") : [];
        } else if (sSugg == "_") {
            lSugg = [];
        } else {
            lSugg = sSugg.gl_expand(m).split("|");
        }
        if (bUppercase && lSugg.length > 0 && m[iGroup].slice(0,1).gl_isUpperCase()) {
            lSugg = capitalizeArray(lSugg);
        }
        // Message
        let sMessage = (sMsg.startsWith("=")) ? oEvalFunc[sMsg.slice(1)](sText, m) : sMsg.gl_expand(m);
        if (bShowRuleId) {
            sMessage += "  ## " + sLineId + " # " + sRuleId;
        }
        //
        return this._createError(nStart, nEnd, sLineId, sRuleId, sOption, sMessage, lSugg, sURL, bContext);
    }

    _createErrorFromTokens (sSugg, nTokenOffset, nLastToken, iFirstToken, nStart, nEnd, sLineId, sRuleId, bCaseSvty, sMsg, sURL, bShowRuleId, sOption, bContext) {
        // suggestions
        let lSugg = [];
        if (sSugg.startsWith("=")) {
            sSugg = oEvalFunc[sSugg.slice(1)](this.lToken, nTokenOffset, nLastToken);
            lSugg = (sSugg) ? sSugg.split("|") : [];
        } else if (sSugg == "_") {
            lSugg = [];
        } else {
            lSugg = this._expand(sSugg, nTokenOffset, nLastToken).split("|");
        }
        if (bCaseSvty && lSugg.length > 0 && this.lToken[iFirstToken]["sValue"].slice(0,1).gl_isUpperCase()) {
            lSugg = capitalizeArray(lSugg);
        }
        // Message
        let sMessage = (sMsg.startsWith("=")) ? oEvalFunc[sMsg.slice(1)](this.lToken, nTokenOffset, nLastToken) : this._expand(sMsg, nTokenOffset, nLastToken);
        if (bShowRuleId) {
            sMessage += " ## " + sLineId + " # " + sRuleId;
        }
        //
        return this._createError(nStart, nEnd, sLineId, sRuleId, sOption, sMessage, lSugg, sURL, bContext);
    }

    _createError (nStart, nEnd, sLineId, sRuleId, sOption, sMessage, lSugg, sURL, bContext) {
        let oErr = {
            "nStart": nStart,
            "nEnd": nEnd,
            "sLineId": sLineId,
            "sRuleId": sRuleId,
            "sType": sOption || "notype",
            "sMessage": sMessage,
            "aSuggestions": lSugg,
            "URL": sURL
        }
        if (bContext) {
            oErr['sUnderlined'] = this.sText0.slice(nStart, nEnd);
            oErr['sBefore'] = this.sText0.slice(Math.max(0,nStart-80), nStart);
            oErr['sAfter'] = this.sText0.slice(nEnd, nEnd+80);
        }
        return oErr;
    }



    _expand (sText, nTokenOffset, nLastToken) {
        let m;
        while ((m = /\\(-?[0-9]+)/.exec(sText)) !== null) {
            if (m[1].slice(0,1) == "-") {
                sText = sText.replace(m[0], this.lToken[nLastToken+parseInt(m[1],10)+1]["sValue"]);
            } else {
                sText = sText.replace(m[0], this.lToken[nTokenOffset+parseInt(m[1],10)]["sValue"]);
            }



        }
        return sText;
    }


    rewriteText (sText, sRepl, iGroup, m, bUppercase) {
        // text processor: write sRepl in sText at iGroup position"
        let ln = m.end[iGroup] - m.start[iGroup];
        let sNew = "";
        if (sRepl === "*") {
            sNew = " ".repeat(ln);
        }
        else if (sRepl === ">" || sRepl === "_" || sRepl === "~") {
            sNew = sRepl + " ".repeat(ln-1);
        }
        else if (sRepl === "@") {
            sNew = "@".repeat(ln);
        }
        else if (sRepl.slice(0,1) === "=") {
            sNew = oEvalFunc[sRepl.slice(1)](sText, m);
            sNew = sNew + " ".repeat(ln-sNew.length);
            if (bUppercase && m[iGroup].slice(0,1).gl_isUpperCase()) {
                sNew = sNew.gl_toCapitalize();
            }
        } else {
            sNew = sRepl.gl_expand(m);
            sNew = sNew + " ".repeat(ln-sNew.length);
        }
        //console.log(sText+"\nstart: "+m.start[iGroup]+" end:"+m.end[iGroup]);
        return sText.slice(0, m.start[iGroup]) + sNew + sText.slice(m.end[iGroup]);
    }

    _tagAndPrepareTokenForRewriting (sWhat, nTokenRewriteStart, nTokenRewriteEnd, nTokenOffset, nLastToken, bCaseSvty, bDebug) {
        // text processor: rewrite tokens between <nTokenRewriteStart> and <nTokenRewriteEnd> position
        if (sWhat === "*") {
            // purge text
            if (nTokenRewriteEnd - nTokenRewriteStart == 0) {
                this.lToken[nTokenRewriteStart]["bToRemove"] = true;
            } else {
                for (let i = nTokenRewriteStart;  i <= nTokenRewriteEnd;  i++) {
                    this.lToken[i]["bToRemove"] = true;
                }
            }
        }
        else if (sWhat === "␣") {
            // merge tokens
            this.lToken[nTokenRewriteStart]["nMergeUntil"] = nTokenRewriteEnd;
        }
        else if (sWhat === "_") {
            // neutralized token
            if (nTokenRewriteEnd - nTokenRewriteStart == 0) {
                this.lToken[nTokenRewriteStart]["sNewValue"] = "_";
            } else {
                for (let i = nTokenRewriteStart;  i <= nTokenRewriteEnd;  i++) {
                    this.lToken[i]["sNewValue"] = "_";
                }
            }
        }
        else {
            if (sWhat.startsWith("=")) {
                sWhat = oEvalFunc[sWhat.slice(1)](this.lToken, nTokenOffset, nLastToken);
            } else {
                sWhat = this._expand(sWhat, nTokenOffset, nLastToken);
            }
            let bUppercase = bCaseSvty && this.lToken[nTokenRewriteStart]["sValue"].slice(0,1).gl_isUpperCase();
            if (nTokenRewriteEnd - nTokenRewriteStart == 0) {
                // one token
                if (bUppercase) {
                    sWhat = sWhat.gl_toCapitalize();
                }
                this.lToken[nTokenRewriteStart]["sNewValue"] = sWhat;
            }
            else {
                // several tokens
                let lTokenValue = sWhat.split("|");
                if (lTokenValue.length != (nTokenRewriteEnd - nTokenRewriteStart + 1)) {
                    console.log("Error. Text processor: number of replacements != number of tokens.");
                    return;
                }

                let j = 0;
                for (let i = nTokenRewriteStart;  i <= nTokenRewriteEnd;  i++) {
                    let sValue = lTokenValue[j];
                    if (!sValue || sValue === "*") {
                        this.lToken[i]["bToRemove"] = true;
                    } else {
                        if (bUppercase) {
                            sValue = sValue.gl_toCapitalize();
                        }
                        this.lToken[i]["sNewValue"] = sValue;
                    }
                    j++;
                }
            }
        }
    }

    rewriteFromTags (bDebug=false) {
        // rewrite the sentence, modify tokens, purge the token list
        if (bDebug) {
            console.log("REWRITE");
        }
        let lNewToken = [];
        let nMergeUntil = 0;
        let dTokenMerger = null;
        for (let [iToken, dToken] of this.lToken.entries()) {
            let bKeepToken = true;
            if (dToken["sType"] != "INFO") {
                if (nMergeUntil && iToken <= nMergeUntil) {
                    dTokenMerger["sValue"] += " ".repeat(dToken["nStart"] - dTokenMerger["nEnd"]) + dToken["sValue"];
                    dTokenMerger["nEnd"] = dToken["nEnd"];
                    if (bDebug) {
                        console.log("  MERGED TOKEN: " + dTokenMerger["sValue"]);
                    }
                    bKeepToken = false;
                }
                if (dToken.hasOwnProperty("nMergeUntil")) {
                    if (iToken > nMergeUntil) { // this token is not already merged with a previous token
                        dTokenMerger = dToken;
                    }
                    if (dToken["nMergeUntil"] > nMergeUntil) {
                        nMergeUntil = dToken["nMergeUntil"];
                    }
                    delete dToken["nMergeUntil"];
                }
                else if (dToken.hasOwnProperty("bToRemove")) {
                    if (bDebug) {
                        console.log("  REMOVED: " + dToken["sValue"]);
                    }
                    this.sSentence = this.sSentence.slice(0, dToken["nStart"]) + " ".repeat(dToken["nEnd"] - dToken["nStart"]) + this.sSentence.slice(dToken["nEnd"]);
                    bKeepToken = false;
                }
            }
            //
            if (bKeepToken) {
                lNewToken.push(dToken);
                if (dToken.hasOwnProperty("sNewValue")) {
                    // rewrite token and sentence
                    if (bDebug) {
                        console.log(dToken["sValue"] + " -> " + dToken["sNewValue"]);
                    }
                    dToken["sRealValue"] = dToken["sValue"];
                    dToken["sValue"] = dToken["sNewValue"];
                    nDiffLen = dToken["sRealValue"].length - dToken["sNewValue"].length;
                    sNewRepl = (nDiffLen >= 0) ? dToken["sNewValue"] + " ".repeat(nDiffLen) : dToken["sNewValue"].slice(0, dToken["sRealValue"].length);
                    this.sSentence = this.sSentence.slice(0,dToken["nStart"]) + sNewRepl + this.sSentence.slice(dToken["nEnd"]);
                    delete dToken["sNewValue"];
                }
            }
            else {
                try {
                    this.dTokenPos.delete(dToken["nStart"]);
                }
                catch (e) {
                    console.log(this.asString());
                    console.log(dToken);
                }
            }
        }
        if (bDebug) {
            console.log("  TEXT REWRITED: " + this.sSentence);
        }
        this.lToken.length = 0;
        this.lToken = lNewToken;
    }
};


//////// Common functions

function option (sOpt) {
    // return true if option sOpt is active
    return _dOptions.get(sOpt);
}


//////// functions to get text outside pattern scope

// warning: check compile_rules.py to understand how it works

function nextword (s, iStart, n) {
    // get the nth word of the input string or empty string
    let z = new RegExp("^(?: +[a-zà-öA-Zø-ÿÀ-Ö0-9Ø-ßĀ-ʯfi-st%_-]+){" + (n-1).toString() + "} +([a-zà-öA-Zø-ÿÀ-Ö0-9Ø-ßĀ-ʯfi-st%_-]+)", "ig");
    let m = z.exec(s.slice(iStart));
................................................................................
    try {
        if (zNegPattern && zNegPattern.test(s)) {
            return false;
        }
        return zPattern.test(s);
    }
    catch (e) {
        console.error(e);
    }
    return false;
}

function look_chk1 (dDA, s, nOffset, zPattern, sPatternGroup1, sNegPatternGroup1=null) {
    // returns True if s has pattern zPattern and m.group(1) has pattern sPatternGroup1
    let m = zPattern.gl_exec2(s, null);
................................................................................
        return false;
    }
    try {
        let sWord = m[1];
        let nPos = m.start[1] + nOffset;
        if (sNegPatternGroup1) {
            return morphex(dDA, [nPos, sWord], sPatternGroup1, sNegPatternGroup1);
        }
        return morph(dDA, [nPos, sWord], sPatternGroup1, false);
    }
    catch (e) {
        console.error(e);
        return false;
    }
}


//////// Analyse groups for regex rules

function displayInfo (dTokenPos, aWord) {
    // for debugging: info of word
    if (!aWord) {
        console.log("> nothing to find");
        return true;
    }
    let lMorph = _oSpellChecker.getMorph(aWord[1]);
    if (lMorph.length === 0) {
        console.log("> not in dictionary");
        return true;
    }
    if (dTokenPos.has(aWord[0])) {
        console.log("DA: " + dTokenPos.get(aWord[0]));
    }
    console.log("FSA: " + lMorph);
    return true;
}

function morph (dTokenPos, aWord, sPattern, sNegPattern, bNoWord=false) {
    // analyse a tuple (position, word), returns true if not sNegPattern in word morphologies and sPattern in word morphologies (disambiguation on)
    if (!aWord) {
        return bNoWord;
    }
    let lMorph = (dTokenPos.has(aWord[0])  &&  dTokenPos.get(aWord[0]))["lMorph"] ? dTokenPos.get(aWord[0])["lMorph"] : _oSpellChecker.getMorph(aWord[1]);
    if (lMorph.length === 0) {
        return false;
    }
    if (sNegPattern) {
        // check negative condition
        if (sNegPattern === "*") {
            // all morph must match sPattern
            return lMorph.every(sMorph  =>  (sMorph.search(sPattern) !== -1));
        }
        else {
            if (lMorph.some(sMorph  =>  (sMorph.search(sNegPattern) !== -1))) {
                return false;
            }
        }
    }
    // search sPattern
    return lMorph.some(sMorph  =>  (sMorph.search(sPattern) !== -1));
}

function analyse (sWord, sPattern, sNegPattern) {
    // analyse a word, returns True if not sNegPattern in word morphologies and sPattern in word morphologies (disambiguation off)
    let lMorph = _oSpellChecker.getMorph(sWord);
    if (lMorph.length === 0) {
        return false;
    }
    if (sNegPattern) {
        // check negative condition
        if (sNegPattern === "*") {
            // all morph must match sPattern
            return lMorph.every(sMorph  =>  (sMorph.search(sPattern) !== -1));
        }
        else {
            if (lMorph.some(sMorph  =>  (sMorph.search(sNegPattern) !== -1))) {
                return false;
            }
        }
    }
    // search sPattern
    return lMorph.some(sMorph  =>  (sMorph.search(sPattern) !== -1));
}


//// Analyse tokens for graph rules

function g_value (dToken, sValues, nLeft=null, nRight=null) {
    // test if <dToken['sValue']> is in sValues (each value should be separated with |)
    let sValue = (nLeft === null) ? "|"+dToken["sValue"]+"|" : "|"+dToken["sValue"].slice(nLeft, nRight)+"|";
    if (sValues.includes(sValues)) {
        return true;
    }
    if (dToken["sValue"].slice(0,2).gl_isTitle()) { // we test only 2 first chars, to make valid words such as "Laissez-les", "Passe-partout".
        if (sValues.includes(sValue.toLowerCase())) {
            return true;
        }
    }
    else if (dToken["sValue"].gl_isUpperCase()) {
        //if sValue.lower() in sValues:
        //    return true;
        sValue = "|"+sValue.slice(1).gl_toCapitalize();
        if (sValues.includes(sValue)) {
            return true;
        }
    }
    return false;
}

function g_morph (dToken, sPattern, sNegPattern="", nLeft=null, nRight=null, bMemorizeMorph=true) {
    // analyse a token, return True if <sNegPattern> not in morphologies and <sPattern> in morphologies
    let lMorph;
    if (dToken.hasOwnProperty("lMorph")) {
        lMorph = dToken["lMorph"];
    }
    else {
        if (nLeft !== null) {
            lMorph = _oSpellChecker.getMorph(dToken["sValue"].slice(nLeft, nRight));
            if (bMemorizeMorph) {
                dToken["lMorph"] = lMorph;
            }
        } else {
            lMorph = _oSpellChecker.getMorph(dToken["sValue"]);
        }
    }
    if (lMorph.length == 0) {
        return false;
    }
    // check negative condition
    if (sNegPattern) {
        if (sNegPattern == "*") {
            // all morph must match sPattern
            return lMorph.every(sMorph  =>  (sMorph.search(sPattern) !== -1));
        }
        else {
            if (lMorph.some(sMorph  =>  (sMorph.search(sNegPattern) !== -1))) {
                return false;
            }
        }
    }
    // search sPattern
    return lMorph.some(sMorph  =>  (sMorph.search(sPattern) !== -1));
}

function g_analyse (dToken, sPattern, sNegPattern="", nLeft=null, nRight=null, bMemorizeMorph=true) {
    // analyse a token, return True if <sNegPattern> not in morphologies and <sPattern> in morphologies
    let lMorph;
    if (nLeft !== null) {
        lMorph = _oSpellChecker.getMorph(dToken["sValue"].slice(nLeft, nRight));
        if (bMemorizeMorph) {
            dToken["lMorph"] = lMorph;
        }
    } else {
        lMorph = _oSpellChecker.getMorph(dToken["sValue"]);
    }
    if (lMorph.length == 0) {
        return false;
    }
    // check negative condition
    if (sNegPattern) {
        if (sNegPattern == "*") {
            // all morph must match sPattern
            return lMorph.every(sMorph  =>  (sMorph.search(sPattern) !== -1));
        }
        else {
            if (lMorph.some(sMorph  =>  (sMorph.search(sNegPattern) !== -1))) {
                return false;
            }
        }
    }
    // search sPattern
    return lMorph.some(sMorph  =>  (sMorph.search(sPattern) !== -1));
}

function g_merged_analyse (dToken1, dToken2, cMerger, sPattern, sNegPattern="", bSetMorph=true) {
    // merge two token values, return True if <sNegPattern> not in morphologies and <sPattern> in morphologies (disambiguation off)
    let lMorph = _oSpellChecker.getMorph(dToken1["sValue"] + cMerger + dToken2["sValue"]);
    if (lMorph.length == 0) {
        return false;
    }
    // check negative condition
    if (sNegPattern) {
        if (sNegPattern == "*") {
            // all morph must match sPattern
            let bResult = lMorph.every(sMorph  =>  (sMorph.search(sPattern) !== -1));
            if (bResult && bSetMorph) {
                dToken1["lMorph"] = lMorph;
            }
            return bResult;
        }
        else {
            if (lMorph.some(sMorph  =>  (sMorph.search(sNegPattern) !== -1))) {
                return false;
            }
        }
    }
    // search sPattern
    let bResult = lMorph.some(sMorph  =>  (sMorph.search(sPattern) !== -1));
    if (bResult && bSetMorph) {
        dToken1["lMorph"] = lMorph;
    }
    return bResult;
}

function g_tag_before (dToken, dTags, sTag) {
    if (dTags.has(sTag)) {
        return false;
    }
    if (dToken["i"] > dTags.get(sTag)[0]) {
        return true;
    }
    return false;
}

function g_tag_after (dToken, dTags, sTag) {
    if (dTags.has(sTag)) {
        return false;
    }
    if (dToken["i"] < dTags.get(sTag)[1]) {
        return true;
    }
    return false;
}

function g_tag (dToken, sTag) {
    return dToken.hasOwnProperty("tags") && dToken["tags"].has(sTag);
}

function g_space_between_tokens (dToken1, dToken2, nMin, nMax=null) {
    let nSpace = dToken2["nStart"] - dToken1["nEnd"]
    if (nSpace < nMin) {
        return false;
    }
    if (nMax !== null && nSpace > nMax) {
        return false;
    }
    return true;
}

function g_token (lToken, i) {
    if (i < 0) {
        return lToken[0];
    }
    if (i >= lToken.length) {
        return lToken[-1];
    }
    return lToken[i];
}


//////// Disambiguator

function select (dTokenPos, nPos, sWord, sPattern, lDefault=null) {
    if (!sWord) {
        return true;
    }
    if (dTokenPos.has(nPos)) {
        return true;
    }
    let lMorph = _oSpellChecker.getMorph(sWord);
    if (lMorph.length === 0  ||  lMorph.length === 1) {
        return true;
    }

    let lSelect = lMorph.filter( sMorph => sMorph.search(sPattern) !== -1 );
    if (lSelect.length > 0) {
        if (lSelect.length != lMorph.length) {
            dTokenPos.set(nPos, lSelect);
        }
    } else if (lDefault) {
        dTokenPos.set(nPos, lDefaul);
    }
    return true;
}

function exclude (dTokenPos, nPos, sWord, sPattern, lDefault=null) {
    if (!sWord) {
        return true;
    }
    if (dTokenPos.has(nPos)) {
        return true;
    }
    let lMorph = _oSpellChecker.getMorph(sWord);
    if (lMorph.length === 0  ||  lMorph.length === 1) {
        return true;
    }
    let lSelect = lMorph.filter( sMorph => sMorph.search(sPattern) === -1 );
    if (lSelect.length > 0) {
        if (lSelect.length != lMorph.length) {
            dTokenPos.set(nPos, lSelect);
        }
    } else if (lDefault) {
        dTokenPos.set(nPos, lDefault);
    }
    return true;
}

function define (dTokenPos, nPos, lMorph) {
    dTokenPos.set(nPos, lMorph);
    return true;
}


//// Disambiguation for graph rules

function g_select (dToken, sPattern, lDefault=null) {
    // select morphologies for <dToken> according to <sPattern>, always return true
    let lMorph = (dToken.hasOwnProperty("lMorph")) ? dToken["lMorph"] : _oSpellChecker.getMorph(dToken["sValue"]);
    if (lMorph.length === 0  || lMorph.length === 1) {
        if (lDefault) {
            dToken["lMorph"] = lDefault;
        }
        return true;
    }
    let lSelect = lMorph.filter( sMorph => sMorph.search(sPattern) !== -1 );
    if (lSelect) {
        if (lSelect.length != lMorph.length) {
            dToken["lMorph"] = lSelect;
        }
    } else if (lDefault) {
        dToken["lMorph"] = lDefault;
    }
    return true;
}

function g_exclude (dToken, sPattern, lDefault=null) {
    // select morphologies for <dToken> according to <sPattern>, always return true
    let lMorph = (dToken.hasOwnProperty("lMorph")) ? dToken["lMorph"] : _oSpellChecker.getMorph(dToken["sValue"]);

    if (lMorph.length === 0  || lMorph.length === 1) {
        if (lDefault) {
            dToken["lMorph"] = lDefault;
        }

        return true;
    }



    let lSelect = lMorph.filter( sMorph => sMorph.search(sPattern) === -1 );
    if (lSelect) {
        if (lSelect.length != lMorph.length) {

            dToken["lMorph"] = lSelect;
        }
    } else if (lDefault) {

        dToken["lMorph"] = lDefault;
    }
    return true;
}

function g_define (dToken, lMorph) {
    // set morphologies of <dToken>, always return true
    dToken["lMorph"] = lMorph;
    return true;
}

function g_define_from (dToken, nLeft=null, nRight=null) {
    if (nLeft !== null) {
        dToken["lMorph"] = _oSpellChecker.getMorph(dToken["sValue"].slice(nLeft, nRight));
    } else {
        dToken["lMorph"] = _oSpellChecker.getMorph(dToken["sValue"]);
    }
    return true;
}


//////// GRAMMAR CHECKER PLUGINS

${pluginsJS}


// generated code, do not edit
const oEvalFunc = {
    // callables for regex rules
${callablesJS}

    // callables for graph rules
${graph_callablesJS}
}


if (typeof(exports) !== 'undefined') {
    exports.lang = gc_engine.lang;
    exports.locales = gc_engine.locales;
    exports.pkg = gc_engine.pkg;
    exports.name = gc_engine.name;
    exports.version = gc_engine.version;
    exports.author = gc_engine.author;
    // init
    exports.load = gc_engine.load;
    exports.getSpellChecker = gc_engine.getSpellChecker;
    // sentence
    exports._zEndOfSentence = gc_engine._zEndOfSentence;
    exports._zBeginOfParagraph = gc_engine._zBeginOfParagraph;
    exports._zEndOfParagraph = gc_engine._zEndOfParagraph;
    exports.getSentenceBoundaries = gc_engine.getSentenceBoundaries;
    // rules


    exports.ignoreRule = gc_engine.ignoreRule;
    exports.resetIgnoreRules = gc_engine.resetIgnoreRules;
    exports.reactivateRule = gc_engine.reactivateRule;
    exports.listRules = gc_engine.listRules;
    exports.getRules = gc_engine.getRules;
    // options

    exports.setOption = gc_engine.setOption;
    exports.setOptions = gc_engine.setOptions;
    exports.getOptions = gc_engine.getOptions;
    exports.getDefaultOptions = gc_engine.getDefaultOptions;
    exports.resetOptions = gc_engine.resetOptions;
    // other
    exports.TextParser = TextParser;
}

Modified gc_core/py/__init__.py from [aeadedff14] to [49f46a05ff].




1
2




from .grammar_checker import *
>
>
>


1
2
3
4
5
"""
Grammar checker
"""

from .grammar_checker import *

Modified gc_core/py/grammar_checker.py from [79ce1061e8] to [634e5c7c61].

1
2

3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
..
18
19
20
21
22
23
24

25
26
27

28
29
30

31
32
33
34
35
36

37
38
39
40
41
42

43
44
45
46
47
48
49
50
51

52
53
54

55
56
57

58
59
60
61
62
63

64
65
66
67
68
69
70
71
72
73
# Grammalecte
# Main class: wrapper


import importlib
import json

from . import text


class GrammarChecker:


    def __init__ (self, sLangCode, sContext="Python"):
        self.sLangCode = sLangCode
        # Grammar checker engine
        self.gce = importlib.import_module("."+sLangCode, "grammalecte")
        self.gce.load(sContext)
        # Spell checker
................................................................................
        self.oSpellChecker = self.gce.getSpellChecker()
        # Lexicographer
        self.oLexicographer = None
        # Text formatter
        self.oTextFormatter = None

    def getGCEngine (self):

        return self.gce

    def getSpellChecker (self):

        return self.oSpellChecker

    def getTextFormatter (self):

        if self.oTextFormatter == None:
            self.tf = importlib.import_module("."+self.sLangCode+".textformatter", "grammalecte")
        self.oTextFormatter = self.tf.TextFormatter()
        return self.oTextFormatter

    def getLexicographer (self):

        if self.oLexicographer == None:
            self.lxg = importlib.import_module("."+self.sLangCode+".lexicographe", "grammalecte")
        self.oLexicographer = self.lxg.Lexicographe(self.oSpellChecker)
        return self.oLexicographer

    def displayGCOptions (self):

        self.gce.displayOptions()

    def getParagraphErrors (self, sText, dOptions=None, bContext=False, bSpellSugg=False, bDebug=False):
        "returns a tuple: (grammar errors, spelling errors)"
        aGrammErrs = self.gce.parse(sText, "FR", bDebug=bDebug, dOptions=dOptions, bContext=bContext)
        aSpellErrs = self.oSpellChecker.parseParagraph(sText, bSpellSugg)
        return aGrammErrs, aSpellErrs

    def generateText (self, sText, bEmptyIfNoErrors=False, bSpellSugg=False, nWidth=100, bDebug=False):

        pass

    def generateTextAsJSON (self, sText, bContext=False, bEmptyIfNoErrors=False, bSpellSugg=False, bReturnText=False, bDebug=False):

        pass

    def generateParagraph (self, sText, dOptions=None, bEmptyIfNoErrors=False, bSpellSugg=False, nWidth=100, bDebug=False):

        aGrammErrs, aSpellErrs = self.getParagraphErrors(sText, dOptions, False, bSpellSugg, bDebug)
        if bEmptyIfNoErrors and not aGrammErrs and not aSpellErrs:
            return ""
        return text.generateParagraph(sText, aGrammErrs, aSpellErrs, nWidth)

    def generateParagraphAsJSON (self, iIndex, sText, dOptions=None, bContext=False, bEmptyIfNoErrors=False, bSpellSugg=False, bReturnText=False, lLineSet=None, bDebug=False):

        aGrammErrs, aSpellErrs = self.getParagraphErrors(sText, dOptions, bContext, bSpellSugg, bDebug)
        aGrammErrs = list(aGrammErrs)
        if bEmptyIfNoErrors and not aGrammErrs and not aSpellErrs:
            return ""
        if lLineSet:
            aGrammErrs, aSpellErrs = text.convertToXY(aGrammErrs, aSpellErrs, lLineSet)
            return json.dumps({ "lGrammarErrors": aGrammErrs, "lSpellingErrors": aSpellErrs }, ensure_ascii=False)
        if bReturnText:
            return json.dumps({ "iParagraph": iIndex, "sText": sText, "lGrammarErrors": aGrammErrs, "lSpellingErrors": aSpellErrs }, ensure_ascii=False)
        return json.dumps({ "iParagraph": iIndex, "lGrammarErrors": aGrammErrs, "lSpellingErrors": aSpellErrs }, ensure_ascii=False)
|
|
>








>







 







>



>



>
|
|
|



>
|
|
|



>









>



>



>






>










1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
"""
Grammalecte, grammar checker
"""

import importlib
import json

from . import text


class GrammarChecker:
    "GrammarChecker: Wrapper for the grammar checker engine"

    def __init__ (self, sLangCode, sContext="Python"):
        self.sLangCode = sLangCode
        # Grammar checker engine
        self.gce = importlib.import_module("."+sLangCode, "grammalecte")
        self.gce.load(sContext)
        # Spell checker
................................................................................
        self.oSpellChecker = self.gce.getSpellChecker()
        # Lexicographer
        self.oLexicographer = None
        # Text formatter
        self.oTextFormatter = None

    def getGCEngine (self):
        "return the grammar checker object"
        return self.gce

    def getSpellChecker (self):
        "return the spell checker object"
        return self.oSpellChecker

    def getTextFormatter (self):
        "load and return the text formatter"
        if self.oTextFormatter is None:
            tf = importlib.import_module("."+self.sLangCode+".textformatter", "grammalecte")
            self.oTextFormatter = tf.TextFormatter()
        return self.oTextFormatter

    def getLexicographer (self):
        "load and return the lexicographer"
        if self.oLexicographer is None:
            lxg = importlib.import_module("."+self.sLangCode+".lexicographe", "grammalecte")
            self.oLexicographer = lxg.Lexicographe(self.oSpellChecker)
        return self.oLexicographer

    def displayGCOptions (self):
        "display the grammar checker options"
        self.gce.displayOptions()

    def getParagraphErrors (self, sText, dOptions=None, bContext=False, bSpellSugg=False, bDebug=False):
        "returns a tuple: (grammar errors, spelling errors)"
        aGrammErrs = self.gce.parse(sText, "FR", bDebug=bDebug, dOptions=dOptions, bContext=bContext)
        aSpellErrs = self.oSpellChecker.parseParagraph(sText, bSpellSugg)
        return aGrammErrs, aSpellErrs

    def generateText (self, sText, bEmptyIfNoErrors=False, bSpellSugg=False, nWidth=100, bDebug=False):
        "[todo]"
        pass

    def generateTextAsJSON (self, sText, bContext=False, bEmptyIfNoErrors=False, bSpellSugg=False, bReturnText=False, bDebug=False):
        "[todo]"
        pass

    def generateParagraph (self, sText, dOptions=None, bEmptyIfNoErrors=False, bSpellSugg=False, nWidth=100, bDebug=False):
        "parse text and return a readable text with underline errors"
        aGrammErrs, aSpellErrs = self.getParagraphErrors(sText, dOptions, False, bSpellSugg, bDebug)
        if bEmptyIfNoErrors and not aGrammErrs and not aSpellErrs:
            return ""
        return text.generateParagraph(sText, aGrammErrs, aSpellErrs, nWidth)

    def generateParagraphAsJSON (self, iIndex, sText, dOptions=None, bContext=False, bEmptyIfNoErrors=False, bSpellSugg=False, bReturnText=False, lLineSet=None, bDebug=False):
        "parse text and return errors as a JSON string"
        aGrammErrs, aSpellErrs = self.getParagraphErrors(sText, dOptions, bContext, bSpellSugg, bDebug)
        aGrammErrs = list(aGrammErrs)
        if bEmptyIfNoErrors and not aGrammErrs and not aSpellErrs:
            return ""
        if lLineSet:
            aGrammErrs, aSpellErrs = text.convertToXY(aGrammErrs, aSpellErrs, lLineSet)
            return json.dumps({ "lGrammarErrors": aGrammErrs, "lSpellingErrors": aSpellErrs }, ensure_ascii=False)
        if bReturnText:
            return json.dumps({ "iParagraph": iIndex, "sText": sText, "lGrammarErrors": aGrammErrs, "lSpellingErrors": aSpellErrs }, ensure_ascii=False)
        return json.dumps({ "iParagraph": iIndex, "lGrammarErrors": aGrammErrs, "lSpellingErrors": aSpellErrs }, ensure_ascii=False)

Modified gc_core/py/lang_core/gc_engine.py from [72ecd7c680] to [a6af5aa7ed].


1
2

3
4
5
6
7
8
9
10
11

12
13
14










15
16
17
18
19
20
21
..
24
25
26
27
28
29
30

31

32
33

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255

256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290

291
292
293

294
295
296
297


298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336

337
338


339
340
341
342
343
344
345
...
347
348
349
350
351
352
353

354

355

356
357

358
359
360
361
362
363
364
365
366
367



368
369



370
371
372
373
374
375









376
377
378








379
380









381
382














383
384
385
386
387
388
389






390
391







392
393
394
395
396
397
398
399
400
401


402
403
404

405
406
407
408
409

















































410
411







































412
413






































414






415
416





417
418
419




420














421












































422
423
424
425
426




























427
428
429


430
431
432

433
434
435











































436



























437
438
439
440


441
442
























































































443
444
















445
446
447

448




449
450
451
452







453
454
455
456





























457
458
459
460
461










462
463
464
465




466
467





























































468
469







470



























471
































472
473
474
475



476
477
478
479
480
481
482
...
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526






























527
528
529











530
531



























































































































































532
533
534

535
536
537

538
539


540
541
542
543
544
545
546
547
548
549
550
551
552
553
554

555
556
557

558
559


560
561






562





















563
564
565
566
567
568









569
570


571








572
573
574


575
576

577
578









579
580
581
582
583
584


585






# Grammalecte
# Grammar checker engine


import re
import sys
import os
import traceback
#import unicodedata
from itertools import chain

from ..graphspell.spellchecker import SpellChecker

from ..graphspell.echo import echo
from . import gc_options












__all__ = [ "lang", "locales", "pkg", "name", "version", "author", \
            "load", "parse", "getSpellChecker", \
            "setOption", "setOptions", "getOptions", "getDefaultOptions", "getOptionsLabels", "resetOptions", "displayOptions", \
            "ignoreRule", "resetIgnoreRules", "reactivateRule", "listRules", "displayRules" ]

__version__ = "${version}"
................................................................................
lang = "${lang}"
locales = ${loc}
pkg = "${implname}"
name = "${name}"
version = "${version}"
author = "${author}"


_rules = None                               # module gc_rules


# data

_sAppContext = ""                           # what software is running
_dOptions = None
_aIgnoredRules = set()
_oSpellChecker = None
_dAnalyses = {}                             # cache for data from dictionary



#### Parsing

def parse (sText, sCountry="${country_default}", bDebug=False, dOptions=None, bContext=False):
    "analyses the paragraph sText and returns list of errors"
    #sText = unicodedata.normalize("NFC", sText)
    aErrors = None
    sAlt = sText
    dDA = {}        # Disambiguisator. Key = position; value = list of morphologies
    dPriority = {}  # Key = position; value = priority
    dOpt = _dOptions  if not dOptions  else dOptions

    # parse paragraph
    try:
        sNew, aErrors = _proofread(sText, sAlt, 0, True, dDA, dPriority, sCountry, dOpt, bDebug, bContext)
        if sNew:
            sText = sNew
    except:
        raise

    # cleanup
    if " " in sText:
        sText = sText.replace(" ", ' ') # nbsp
    if " " in sText:
        sText = sText.replace(" ", ' ') # nnbsp
    if "'" in sText:
        sText = sText.replace("'", "’")
    if "‑" in sText:
        sText = sText.replace("‑", "-") # nobreakdash

    # parse sentences
    for iStart, iEnd in _getSentenceBoundaries(sText):
        if 4 < (iEnd - iStart) < 2000:
            dDA.clear()
            try:
                _, errs = _proofread(sText[iStart:iEnd], sAlt[iStart:iEnd], iStart, False, dDA, dPriority, sCountry, dOpt, bDebug, bContext)
                aErrors.update(errs)
            except:
                raise
    return aErrors.values() # this is a view (iterable)


def _getSentenceBoundaries (sText):
    iStart = _zBeginOfParagraph.match(sText).end()
    for m in _zEndOfSentence.finditer(sText):
        yield (iStart, m.end())
        iStart = m.end()


def _proofread (s, sx, nOffset, bParagraph, dDA, dPriority, sCountry, dOptions, bDebug, bContext):
    dErrs = {}
    bChange = False
    bIdRule = option('idrule')

    for sOption, lRuleGroup in _getRules(bParagraph):
        if not sOption or dOptions.get(sOption, False):
            for zRegex, bUppercase, sLineId, sRuleId, nPriority, lActions in lRuleGroup:
                if sRuleId not in _aIgnoredRules:
                    for m in zRegex.finditer(s):
                        bCondMemo = None
                        for sFuncCond, cActionType, sWhat, *eAct in lActions:
                            # action in lActions: [ condition, action type, replacement/suggestion/action[, iGroup[, message, URL]] ]
                            try:
                                bCondMemo = not sFuncCond or globals()[sFuncCond](s, sx, m, dDA, sCountry, bCondMemo)
                                if bCondMemo:
                                    if cActionType == "-":
                                        # grammar error
                                        nErrorStart = nOffset + m.start(eAct[0])
                                        if nErrorStart not in dErrs or nPriority > dPriority[nErrorStart]:
                                            dErrs[nErrorStart] = _createError(s, sx, sWhat, nOffset, m, eAct[0], sLineId, sRuleId, bUppercase, eAct[1], eAct[2], bIdRule, sOption, bContext)
                                            dPriority[nErrorStart] = nPriority
                                    elif cActionType == "~":
                                        # text processor
                                        s = _rewrite(s, sWhat, eAct[0], m, bUppercase)
                                        bChange = True
                                        if bDebug:
                                            echo("~ " + s + "  -- " + m.group(eAct[0]) + "  # " + sLineId)
                                    elif cActionType == "=":
                                        # disambiguation
                                        globals()[sWhat](s, m, dDA)
                                        if bDebug:
                                            echo("= " + m.group(0) + "  # " + sLineId + "\nDA: " + str(dDA))
                                    elif cActionType == ">":
                                        # we do nothing, this test is just a condition to apply all following actions
                                        pass
                                    else:
                                        echo("# error: unknown action at " + sLineId)
                                elif cActionType == ">":
                                    break
                            except Exception as e:
                                raise Exception(str(e), "# " + sLineId + " # " + sRuleId)
    if bChange:
        return (s, dErrs)
    return (False, dErrs)


def _createWriterError (s, sx, sRepl, nOffset, m, iGroup, sLineId, sRuleId, bUppercase, sMsg, sURL, bIdRule, sOption, bContext):
    "error for Writer (LO/OO)"
    xErr = SingleProofreadingError()
    #xErr = uno.createUnoStruct( "com.sun.star.linguistic2.SingleProofreadingError" )
    xErr.nErrorStart = nOffset + m.start(iGroup)
    xErr.nErrorLength = m.end(iGroup) - m.start(iGroup)
    xErr.nErrorType = PROOFREADING
    xErr.aRuleIdentifier = sRuleId
    # suggestions
    if sRepl[0:1] == "=":
        sugg = globals()[sRepl[1:]](s, m)
        if sugg:
            if bUppercase and m.group(iGroup)[0:1].isupper():
                xErr.aSuggestions = tuple(map(str.capitalize, sugg.split("|")))
            else:
                xErr.aSuggestions = tuple(sugg.split("|"))
        else:
            xErr.aSuggestions = ()
    elif sRepl == "_":
        xErr.aSuggestions = ()
    else:
        if bUppercase and m.group(iGroup)[0:1].isupper():
            xErr.aSuggestions = tuple(map(str.capitalize, m.expand(sRepl).split("|")))
        else:
            xErr.aSuggestions = tuple(m.expand(sRepl).split("|"))
    # Message
    if sMsg[0:1] == "=":
        sMessage = globals()[sMsg[1:]](s, m)
    else:
        sMessage = m.expand(sMsg)
    xErr.aShortComment = sMessage   # sMessage.split("|")[0]     # in context menu
    xErr.aFullComment = sMessage   # sMessage.split("|")[-1]    # in dialog
    if bIdRule:
        xErr.aShortComment += "  # " + sLineId + " # " + sRuleId
    # URL
    if sURL:
        p = PropertyValue()
        p.Name = "FullCommentURL"
        p.Value = sURL
        xErr.aProperties = (p,)
    else:
        xErr.aProperties = ()
    return xErr


def _createDictError (s, sx, sRepl, nOffset, m, iGroup, sLineId, sRuleId, bUppercase, sMsg, sURL, bIdRule, sOption, bContext):
    "error as a dictionary"
    dErr = {}
    dErr["nStart"] = nOffset + m.start(iGroup)
    dErr["nEnd"] = nOffset + m.end(iGroup)
    dErr["sLineId"] = sLineId
    dErr["sRuleId"] = sRuleId
    dErr["sType"] = sOption  if sOption  else "notype"
    # suggestions
    if sRepl[0:1] == "=":
        sugg = globals()[sRepl[1:]](s, m)
        if sugg:
            if bUppercase and m.group(iGroup)[0:1].isupper():
                dErr["aSuggestions"] = list(map(str.capitalize, sugg.split("|")))
            else:
                dErr["aSuggestions"] = sugg.split("|")
        else:
            dErr["aSuggestions"] = ()
    elif sRepl == "_":
        dErr["aSuggestions"] = ()
    else:
        if bUppercase and m.group(iGroup)[0:1].isupper():
            dErr["aSuggestions"] = list(map(str.capitalize, m.expand(sRepl).split("|")))
        else:
            dErr["aSuggestions"] = m.expand(sRepl).split("|")
    # Message
    if sMsg[0:1] == "=":
        sMessage = globals()[sMsg[1:]](s, m)
    else:
        sMessage = m.expand(sMsg)
    dErr["sMessage"] = sMessage
    if bIdRule:
        dErr["sMessage"] += "  # " + sLineId + " # " + sRuleId
    # URL
    dErr["URL"] = sURL  if sURL  else ""
    # Context
    if bContext:
        dErr['sUnderlined'] = sx[m.start(iGroup):m.end(iGroup)]
        dErr['sBefore'] = sx[max(0,m.start(iGroup)-80):m.start(iGroup)]
        dErr['sAfter'] = sx[m.end(iGroup):m.end(iGroup)+80]
    return dErr


def _rewrite (s, sRepl, iGroup, m, bUppercase):
    "text processor: write sRepl in s at iGroup position"
    nLen = m.end(iGroup) - m.start(iGroup)
    if sRepl == "*":
        sNew = " " * nLen
    elif sRepl == ">" or sRepl == "_" or sRepl == "~":
        sNew = sRepl + " " * (nLen-1)
    elif sRepl == "@":
        sNew = "@" * nLen
    elif sRepl[0:1] == "=":
        sNew = globals()[sRepl[1:]](s, m)
        sNew = sNew + " " * (nLen-len(sNew))
        if bUppercase and m.group(iGroup)[0:1].isupper():
            sNew = sNew.capitalize()
    else:
        sNew = m.expand(sRepl)
        sNew = sNew + " " * (nLen-len(sNew))
    return s[0:m.start(iGroup)] + sNew + s[m.end(iGroup):]


def ignoreRule (sRuleId):
    _aIgnoredRules.add(sRuleId)


def resetIgnoreRules ():
    _aIgnoredRules.clear()


def reactivateRule (sRuleId):
    _aIgnoredRules.discard(sRuleId)



def listRules (sFilter=None):
    "generator: returns typle (sOption, sLineId, sRuleId)"
    if sFilter:
        try:
            zFilter = re.compile(sFilter)
        except:
            echo("# Error. List rules: wrong regex.")
            sFilter = None
    for sOption, lRuleGroup in chain(_getRules(True), _getRules(False)):
        for _, _, sLineId, sRuleId, _, _ in lRuleGroup:
            if not sFilter or zFilter.search(sRuleId):
                yield (sOption, sLineId, sRuleId)


def displayRules (sFilter=None):
    echo("List of rules. Filter: << " + str(sFilter) + " >>")
    for sOption, sLineId, sRuleId in listRules(sFilter):
        echo("{:<10} {:<10} {}".format(sOption, sLineId, sRuleId))


#### init

try:
    # LibreOffice / OpenOffice
    from com.sun.star.linguistic2 import SingleProofreadingError
    from com.sun.star.text.TextMarkupType import PROOFREADING
    from com.sun.star.beans import PropertyValue
    #import lightproof_handler_${implname} as opt
    _createError = _createWriterError
except ImportError:
    _createError = _createDictError


def load (sContext="Python"):

    global _oSpellChecker
    global _sAppContext
    global _dOptions

    try:
        _oSpellChecker = SpellChecker("${lang}", "${dic_main_filename_py}", "${dic_extended_filename_py}", "${dic_community_filename_py}", "${dic_personal_filename_py}")
        _sAppContext = sContext
        _dOptions = dict(gc_options.getOptions(sContext))   # duplication necessary, to be able to reset to default


    except:
        traceback.print_exc()


def setOption (sOpt, bVal):
    if sOpt in _dOptions:
        _dOptions[sOpt] = bVal


def setOptions (dOpt):
    for sKey, bVal in dOpt.items():
        if sKey in _dOptions:
            _dOptions[sKey] = bVal


def getOptions ():
    return _dOptions


def getDefaultOptions ():
    return dict(gc_options.getOptions(_sAppContext))


def getOptionsLabels (sLang):
    return gc_options.getUI(sLang)


def displayOptions (sLang):
    echo("List of options")
    echo("\n".join( [ k+":\t"+str(v)+"\t"+gc_options.getUI(sLang).get(k, ("?", ""))[0]  for k, v  in sorted(_dOptions.items()) ] ))
    echo("")


def resetOptions ():
    global _dOptions
    _dOptions = dict(gc_options.getOptions(_sAppContext))


def getSpellChecker ():

    return _oSpellChecker




def _getRules (bParagraph):
    try:
        if not bParagraph:
            return _rules.lSentenceRules
        return _rules.lParagraphRules
    except:
................................................................................
    if not bParagraph:
        return _rules.lSentenceRules
    return _rules.lParagraphRules


def _loadRules ():
    from . import gc_rules

    global _rules

    _rules = gc_rules

    # compile rules regex
    for lRuleGroup in chain(_rules.lParagraphRules, _rules.lSentenceRules):

        for rule in lRuleGroup[1]:
            try:
                rule[0] = re.compile(rule[0])
            except:
                echo("Bad regular expression in # " + str(rule[2]))
                rule[0] = "(?i)<Grammalecte>"


def _getPath ():
    return os.path.join(os.path.dirname(sys.modules[__name__].__file__), __name__ + ".py")









#### common functions

# common regexes
_zEndOfSentence = re.compile('([.?!:;…][ .?!… »”")]*|.$)')
_zBeginOfParagraph = re.compile("^\W*")









_zEndOfParagraph = re.compile("\W*$")
_zNextWord = re.compile(" +(\w[\w-]*)")
_zPrevWord = re.compile("(\w[\w-]*) +$")



















def option (sOpt):
    "return True if option sOpt is active"














    return _dOptions.get(sOpt, False)


def displayInfo (dDA, tWord):
    "for debugging: retrieve info of word"
    if not tWord:
        echo("> nothing to find")






        return True
    if tWord[1] not in _dAnalyses and not _storeMorphFromFSA(tWord[1]):







        echo("> not in FSA")
        return True
    if tWord[0] in dDA:
        echo("DA: " + str(dDA[tWord[0]]))
    echo("FSA: " + str(_dAnalyses[tWord[1]]))
    return True


def _storeMorphFromFSA (sWord):
    "retrieves morphologies list from _oSpellChecker -> _dAnalyses"


    global _dAnalyses
    _dAnalyses[sWord] = _oSpellChecker.getMorph(sWord)
    return True  if _dAnalyses[sWord]  else False



def morph (dDA, tWord, sPattern, bStrict=True, bNoWord=False):
    "analyse a tuple (position, word), return True if sPattern in morphologies (disambiguation on)"
    if not tWord:

















































        return bNoWord
    if tWord[1] not in _dAnalyses and not _storeMorphFromFSA(tWord[1]):







































        return False
    lMorph = dDA[tWord[0]]  if tWord[0] in dDA  else _dAnalyses[tWord[1]]






































    if not lMorph:






        return False
    p = re.compile(sPattern)





    if bStrict:
        return all(p.search(s)  for s in lMorph)
    return any(p.search(s)  for s in lMorph)
































































def morphex (dDA, tWord, sPattern, sNegPattern, bNoWord=False):
    "analyse a tuple (position, word), returns True if not sNegPattern in word morphologies and sPattern in word morphologies (disambiguation on)"
    if not tWord:
        return bNoWord
    if tWord[1] not in _dAnalyses and not _storeMorphFromFSA(tWord[1]):




























        return False
    lMorph = dDA[tWord[0]]  if tWord[0] in dDA  else _dAnalyses[tWord[1]]
    # check negative condition


    np = re.compile(sNegPattern)
    if any(np.search(s)  for s in lMorph):
        return False

    # search sPattern
    p = re.compile(sPattern)
    return any(p.search(s)  for s in lMorph)








































































def analyse (sWord, sPattern, bStrict=True):
    "analyse a word, return True if sPattern in morphologies (disambiguation off)"
    if sWord not in _dAnalyses and not _storeMorphFromFSA(sWord):


        return False
    if not _dAnalyses[sWord]:
























































































        return False
    p = re.compile(sPattern)
















    if bStrict:
        return all(p.search(s)  for s in _dAnalyses[sWord])
    return any(p.search(s)  for s in _dAnalyses[sWord])







def analysex (sWord, sPattern, sNegPattern):
    "analyse a word, returns True if not sNegPattern in word morphologies and sPattern in word morphologies (disambiguation off)"
    if sWord not in _dAnalyses and not _storeMorphFromFSA(sWord):







        return False
    # check negative condition
    np = re.compile(sNegPattern)
    if any(np.search(s)  for s in _dAnalyses[sWord]):





























        return False
    # search sPattern
    p = re.compile(sPattern)
    return any(p.search(s)  for s in _dAnalyses[sWord])












def stem (sWord):
    "returns a list of sWord's stems"
    if not sWord:




        return []
    if sWord not in _dAnalyses and not _storeMorphFromFSA(sWord):





























































        return []
    return [ s[1:s.find(" ")]  for s in _dAnalyses[sWord] ]




































































## functions to get text outside pattern scope

# warning: check compile_rules.py to understand how it works




def nextword (s, iStart, n):
    "get the nth word of the input string or empty string"
    m = re.match("(?: +[\\w%-]+){" + str(n-1) + "} +([\\w%-]+)", s[iStart:])
    if not m:
        return None
    return (iStart+m.start(1), m.group(1))

................................................................................
    if sNegPattern and re.search(sNegPattern, s):
        return False
    if re.search(sPattern, s):
        return True
    return False


def look_chk1 (dDA, s, nOffset, sPattern, sPatternGroup1, sNegPatternGroup1=None):
    "returns True if s has pattern sPattern and m.group(1) has pattern sPatternGroup1"
    m = re.search(sPattern, s)
    if not m:
        return False
    try:
        sWord = m.group(1)
        nPos = m.start(1) + nOffset
    except:
        return False






























    if sNegPatternGroup1:
        return morphex(dDA, (nPos, sWord), sPatternGroup1, sNegPatternGroup1)
    return morph(dDA, (nPos, sWord), sPatternGroup1, False)








































































































































































#### Disambiguator

def select (dDA, nPos, sWord, sPattern, lDefault=None):

    if not sWord:
        return True
    if nPos in dDA:

        return True
    if sWord not in _dAnalyses and not _storeMorphFromFSA(sWord):


        return True
    if len(_dAnalyses[sWord]) == 1:
        return True
    lSelect = [ sMorph  for sMorph in _dAnalyses[sWord]  if re.search(sPattern, sMorph) ]
    if lSelect:
        if len(lSelect) != len(_dAnalyses[sWord]):
            dDA[nPos] = lSelect
            #echo("= "+sWord+" "+str(dDA.get(nPos, "null")))
    elif lDefault:
        dDA[nPos] = lDefault
        #echo("= "+sWord+" "+str(dDA.get(nPos, "null")))
    return True


def exclude (dDA, nPos, sWord, sPattern, lDefault=None):

    if not sWord:
        return True
    if nPos in dDA:

        return True
    if sWord not in _dAnalyses and not _storeMorphFromFSA(sWord):


        return True
    if len(_dAnalyses[sWord]) == 1:






        return True





















    lSelect = [ sMorph  for sMorph in _dAnalyses[sWord]  if not re.search(sPattern, sMorph) ]
    if lSelect:
        if len(lSelect) != len(_dAnalyses[sWord]):
            dDA[nPos] = lSelect
            #echo("= "+sWord+" "+str(dDA.get(nPos, "null")))
    elif lDefault:









        dDA[nPos] = lDefault
        #echo("= "+sWord+" "+str(dDA.get(nPos, "null")))


    return True










def define (dDA, nPos, lMorph):


    dDA[nPos] = lMorph
    #echo("= "+str(nPos)+" "+str(dDA[nPos]))

    return True











#### GRAMMAR CHECKER PLUGINS

${plugins}




${callables}





>
|
|
>









>



>
>
>
>
>
>
>
>
>
>







 







>

>

<
>


<

<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|


<
<

>

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

>



>




>
>




<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

>


>
>







 







>

>

>

|
>
|
|
|
|
|
|


<
<
>
>
>


>
>
>

<

<
<
<
>
>
>
>
>
>
>
>
>
|
<
<
>
>
>
>
>
>
>
>


>
>
>
>
>
>
>
>
>
|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|


<
<
<
<
>
>
>
>
>
>
|
<
>
>
>
>
>
>
>
|
<
<
<
<
<


<
<
>
>
|
<
<
>


<
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
|
<
>
>
>
>
>
|
<
<
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
<
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
<
>
>
|
<
<
>
|
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

<
<
<
>
>
|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
<
>
|
>
>
>
>

<
<
<
>
>
>
>
>
>
>
|
<
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
<
<

>
>
>
>
>
>
>
>
>
>
|
<
<
<
>
>
>
>
|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|



>
>
>







 







|









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
<
>
>
>
>
>
>
>
>
>
>
>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

|
>


|
>

<
>
>

<
<
|

|
|
<

|
<



|
>


|
>

<
>
>

<
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

|
|
<

>
>
>
>
>
>
>
>
>
|
<
>
>
|
>
>
>
>
>
>
>
>


<
>
>
|
<
>


>
>
>
>
>
>
>
>
>






>
>

>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
..
37
38
39
40
41
42
43
44
45
46
47

48
49
50

51









52










































































































































































































53
54
55


56
57
58

































59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74


































75
76
77
78
79
80
81
82
83
84
85
86
87
..
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111


112
113
114
115
116
117
118
119
120

121



122
123
124
125
126
127
128
129
130
131


132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168




169
170
171
172
173
174
175

176
177
178
179
180
181
182
183





184
185


186
187
188


189
190
191



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241

242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281

282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327

328
329
330
331
332
333


334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398




399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427


428
429
430


431
432


433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504



505
506
507

508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596

597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613


614
615
616
617
618
619
620



621
622
623
624
625
626
627
628



629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658



659
660
661
662
663
664
665
666
667
668
669
670



671
672
673
674
675

676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737

738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
...
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894


895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071

1072
1073
1074


1075
1076
1077
1078

1079
1080

1081
1082
1083
1084
1085
1086
1087
1088
1089
1090

1091
1092
1093

1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125

1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136

1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149

1150
1151
1152

1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
"""
Grammalecte
Grammar checker engine
"""

import re
import sys
import os
import traceback
#import unicodedata
from itertools import chain

from ..graphspell.spellchecker import SpellChecker
from ..graphspell.tokenizer import Tokenizer
from ..graphspell.echo import echo
from . import gc_options

try:
    # LibreOffice / OpenOffice
    from com.sun.star.linguistic2 import SingleProofreadingError
    from com.sun.star.text.TextMarkupType import PROOFREADING
    from com.sun.star.beans import PropertyValue
    #import lightproof_handler_${implname} as opt
    _bWriterError = True
except ImportError:
    _bWriterError = False


__all__ = [ "lang", "locales", "pkg", "name", "version", "author", \
            "load", "parse", "getSpellChecker", \
            "setOption", "setOptions", "getOptions", "getDefaultOptions", "getOptionsLabels", "resetOptions", "displayOptions", \
            "ignoreRule", "resetIgnoreRules", "reactivateRule", "listRules", "displayRules" ]

__version__ = "${version}"
................................................................................
lang = "${lang}"
locales = ${loc}
pkg = "${implname}"
name = "${name}"
version = "${version}"
author = "${author}"

# Modules
_rules = None                               # module gc_rules
_rules_graph = None                         # module gc_rules_graph


# Data
_sAppContext = ""                           # what software is running
_dOptions = None

_oSpellChecker = None









_oTokenizer = None










































































































































































































_aIgnoredRules = set()





#### Initialization


































def load (sContext="Python"):
    "initialization of the grammar checker"
    global _oSpellChecker
    global _sAppContext
    global _dOptions
    global _oTokenizer
    try:
        _oSpellChecker = SpellChecker("${lang}", "${dic_main_filename_py}", "${dic_extended_filename_py}", "${dic_community_filename_py}", "${dic_personal_filename_py}")
        _sAppContext = sContext
        _dOptions = dict(gc_options.getOptions(sContext))   # duplication necessary, to be able to reset to default
        _oTokenizer = _oSpellChecker.getTokenizer()
        _oSpellChecker.activateStorage()
    except:
        traceback.print_exc()




































def getSpellChecker ():
    "return the spellchecker object"
    return _oSpellChecker


#### Rules

def _getRules (bParagraph):
    try:
        if not bParagraph:
            return _rules.lSentenceRules
        return _rules.lParagraphRules
    except:
................................................................................
    if not bParagraph:
        return _rules.lSentenceRules
    return _rules.lParagraphRules


def _loadRules ():
    from . import gc_rules
    from . import gc_rules_graph
    global _rules
    global _rules_graph
    _rules = gc_rules
    _rules_graph = gc_rules_graph
    # compile rules regex
    for sOption, lRuleGroup in chain(_rules.lParagraphRules, _rules.lSentenceRules):
        if sOption != "@@@@":
            for aRule in lRuleGroup:
                try:
                    aRule[0] = re.compile(aRule[0])
                except:
                    echo("Bad regular expression in # " + str(aRule[2]))
                    aRule[0] = "(?i)<Grammalecte>"




def ignoreRule (sRuleId):
    "disable rule <sRuleId>"
    _aIgnoredRules.add(sRuleId)


def resetIgnoreRules ():
    "clear all ignored rules"
    _aIgnoredRules.clear()






def reactivateRule (sRuleId):
    "(re)activate rule <sRuleId>"
    _aIgnoredRules.discard(sRuleId)


def listRules (sFilter=None):
    "generator: returns typle (sOption, sLineId, sRuleId)"
    if sFilter:
        try:
            zFilter = re.compile(sFilter)


        except:
            echo("# Error. List rules: wrong regex.")
            sFilter = None
    for sOption, lRuleGroup in chain(_getRules(True), _getRules(False)):
        if sOption != "@@@@":
            for _, _, sLineId, sRuleId, _, _ in lRuleGroup:
                if not sFilter or zFilter.search(sRuleId):
                    yield (sOption, sLineId, sRuleId)


def displayRules (sFilter=None):
    "display the name of rules, with the filter <sFilter>"
    echo("List of rules. Filter: << " + str(sFilter) + " >>")
    for sOption, sLineId, sRuleId in listRegexRules(sFilter):
        echo("{:<10} {:<10} {}".format(sOption, sLineId, sRuleId))


#### Options

def setOption (sOpt, bVal):

    "set option <sOpt> with <bVal> if it exists"
    if sOpt in _dOptions:
        _dOptions[sOpt] = bVal


def setOptions (dOpt):
    "update the dictionary of options with <dOpt>"
    for sKey, bVal in dOpt.items():
        if sKey in _dOptions:
            _dOptions[sKey] = bVal


def getOptions ():
    "return the dictionary of current options"
    return _dOptions






def getDefaultOptions ():
    "return the dictionary of default options"
    return dict(gc_options.getOptions(_sAppContext))


def getOptionsLabels (sLang):
    "return options labels"

    return gc_options.getUI(sLang)


def displayOptions (sLang):
    "display the list of grammar checking options"
    echo("List of options")
    echo("\n".join( [ k+":\t"+str(v)+"\t"+gc_options.getUI(sLang).get(k, ("?", ""))[0]  for k, v  in sorted(_dOptions.items()) ] ))
    echo("")









def resetOptions ():
    "set options to default values"
    global _dOptions


    _dOptions = dict(gc_options.getOptions(_sAppContext))





#### Parsing

_zEndOfSentence = re.compile(r'([.?!:;…][ .?!… »”")]*|.$)')
_zBeginOfParagraph = re.compile(r"^\W*")
_zEndOfParagraph = re.compile(r"\W*$")

def _getSentenceBoundaries (sText):
    iStart = _zBeginOfParagraph.match(sText).end()
    for m in _zEndOfSentence.finditer(sText):
        yield (iStart, m.end())
        iStart = m.end()


def parse (sText, sCountry="${country_default}", bDebug=False, dOptions=None, bContext=False):
    "init point to analyze a text"
    oText = TextParser(sText)
    return oText.parse(sCountry, bDebug, dOptions, bContext)


#### TEXT PARSER

class TextParser:
    "Text parser"

    def __init__ (self, sText):
        self.sText = sText
        self.sText0 = sText
        self.sSentence = ""
        self.sSentence0 = ""
        self.nOffsetWithinParagraph = 0
        self.lToken = []
        self.dTokenPos = {}
        self.dTags = {}
        self.dError = {}
        self.dErrorPriority = {}  # Key = position; value = priority

    def __str__ (self):
        s = "===== TEXT =====\n"
        s += "sentence: " + self.sSentence0 + "\n"
        s += "now:      " + self.sSentence  + "\n"
        for dToken in self.lToken:
            s += '#{i}\t{nStart}:{nEnd}\t{sValue}\t{sType}'.format(**dToken)
            if "lMorph" in dToken:
                s += "\t" + str(dToken["lMorph"])
            if "tags" in dToken:
                s += "\t" + str(dToken["tags"])
            s += "\n"
        #for nPos, dToken in self.dTokenPos.items():
        #    s += "{}\t{}\n".format(nPos, dToken)
        return s


    def parse (self, sCountry="${country_default}", bDebug=False, dOptions=None, bContext=False):
        "analyses the paragraph sText and returns list of errors"
        #sText = unicodedata.normalize("NFC", sText)
        dOpt = dOptions or _dOptions
        bShowRuleId = option('idrule')

        # parse paragraph
        try:
            self.parseText(self.sText, self.sText0, True, 0, sCountry, dOpt, bShowRuleId, bDebug, bContext)
        except:
            raise

        # cleanup
        sText = self.sText
        if " " in sText:
            sText = sText.replace(" ", ' ') # nbsp
        if " " in sText:
            sText = sText.replace(" ", ' ') # nnbsp
        if "'" in sText:
            sText = sText.replace("'", "’")
        if "‑" in sText:
            sText = sText.replace("‑", "-") # nobreakdash

        # parse sentences
        for iStart, iEnd in _getSentenceBoundaries(sText):
            if 4 < (iEnd - iStart) < 2000:
                try:
                    self.sSentence = sText[iStart:iEnd]
                    self.sSentence0 = self.sText0[iStart:iEnd]
                    self.nOffsetWithinParagraph = iStart
                    self.lToken = list(_oTokenizer.genTokens(self.sSentence, True))
                    self.dTokenPos = { dToken["nStart"]: dToken  for dToken in self.lToken  if dToken["sType"] != "INFO" }
                    self.parseText(self.sSentence, self.sSentence0, False, iStart, sCountry, dOpt, bShowRuleId, bDebug, bContext)
                except:
                    raise
        return self.dError.values() # this is a view (iterable)

    def parseText (self, sText, sText0, bParagraph, nOffset, sCountry, dOptions, bShowRuleId, bDebug, bContext):
        bChange = False

        for sOption, lRuleGroup in _getRules(bParagraph):
            if sOption == "@@@@":
                # graph rules
                if not bParagraph and bChange:
                    self.update(sText, bDebug)
                    bChange = False
                for sGraphName, sLineId in lRuleGroup:
                    if sGraphName not in dOptions or dOptions[sGraphName]:
                        if bDebug:
                            echo("\n>>>> GRAPH: " + sGraphName + " " + sLineId)
                        sText = self.parseGraph(_rules_graph.dAllGraph[sGraphName], sCountry, dOptions, bShowRuleId, bDebug, bContext)
            elif not sOption or dOptions.get(sOption, False):
                # regex rules
                for zRegex, bUppercase, sLineId, sRuleId, nPriority, lActions in lRuleGroup:
                    if sRuleId not in _aIgnoredRules:
                        for m in zRegex.finditer(sText):
                            bCondMemo = None
                            for sFuncCond, cActionType, sWhat, *eAct in lActions:
                                # action in lActions: [ condition, action type, replacement/suggestion/action[, iGroup[, message, URL]] ]
                                try:
                                    bCondMemo = not sFuncCond or globals()[sFuncCond](sText, sText0, m, self.dTokenPos, sCountry, bCondMemo)
                                    if bCondMemo:
                                        if bDebug:
                                            echo("RULE: " + sLineId)
                                        if cActionType == "-":
                                            # grammar error
                                            nErrorStart = nOffset + m.start(eAct[0])
                                            if nErrorStart not in self.dError or nPriority > self.dErrorPriority.get(nErrorStart, -1):
                                                self.dError[nErrorStart] = self._createErrorFromRegex(sText, sText0, sWhat, nOffset, m, eAct[0], sLineId, sRuleId, bUppercase, eAct[1], eAct[2], bShowRuleId, sOption, bContext)
                                                self.dErrorPriority[nErrorStart] = nPriority
                                        elif cActionType == "~":
                                            # text processor
                                            sText = self.rewriteText(sText, sWhat, eAct[0], m, bUppercase)
                                            bChange = True
                                            if bDebug:
                                                echo("~ " + sText + "  -- " + m.group(eAct[0]) + "  # " + sLineId)
                                        elif cActionType == "=":
                                            # disambiguation
                                            if not bParagraph:
                                                globals()[sWhat](sText, m, self.dTokenPos)
                                                if bDebug:
                                                    echo("= " + m.group(0) + "  # " + sLineId)
                                        elif cActionType == ">":
                                            # we do nothing, this test is just a condition to apply all following actions
                                            pass
                                        else:

                                            echo("# error: unknown action at " + sLineId)
                                    elif cActionType == ">":
                                        break
                                except Exception as e:
                                    raise Exception(str(e), "# " + sLineId + " # " + sRuleId)
        if bChange:


            if bParagraph:
                self.sText = sText
            else:
                self.sSentence = sText

    def update (self, sSentence, bDebug=False):
        "update <sSentence> and retokenize"
        self.sSentence = sSentence
        lNewToken = list(_oTokenizer.genTokens(sSentence, True))
        for dToken in lNewToken:
            if "lMorph" in self.dTokenPos.get(dToken["nStart"], {}):
                dToken["lMorph"] = self.dTokenPos[dToken["nStart"]]["lMorph"]
            if "tags" in self.dTokenPos.get(dToken["nStart"], {}):
                dToken["tags"] = self.dTokenPos[dToken["nStart"]]["tags"]
        self.lToken = lNewToken
        self.dTokenPos = { dToken["nStart"]: dToken  for dToken in self.lToken  if dToken["sType"] != "INFO" }
        if bDebug:
            echo("UPDATE:")
            echo(self)

    def _getNextPointers (self, dToken, dGraph, dPointer, bDebug=False):
        "generator: return nodes where <dToken> “values” match <dNode> arcs"
        dNode = dPointer["dNode"]
        iNode1 = dPointer["iNode1"]
        bTokenFound = False
        # token value
        if dToken["sValue"] in dNode:
            if bDebug:
                echo("  MATCH: " + dToken["sValue"])
            yield { "iNode1": iNode1, "dNode": dGraph[dNode[dToken["sValue"]]] }
            bTokenFound = True
        if dToken["sValue"][0:2].istitle(): # we test only 2 first chars, to make valid words such as "Laissez-les", "Passe-partout".
            sValue = dToken["sValue"].lower()
            if sValue in dNode:
                if bDebug:
                    echo("  MATCH: " + sValue)
                yield { "iNode1": iNode1, "dNode": dGraph[dNode[sValue]] }
                bTokenFound = True
        elif dToken["sValue"].isupper():
            sValue = dToken["sValue"].lower()
            if sValue in dNode:
                if bDebug:
                    echo("  MATCH: " + sValue)
                yield { "iNode1": iNode1, "dNode": dGraph[dNode[sValue]] }
                bTokenFound = True
            sValue = dToken["sValue"].capitalize()
            if sValue in dNode:
                if bDebug:
                    echo("  MATCH: " + sValue)
                yield { "iNode1": iNode1, "dNode": dGraph[dNode[sValue]] }
                bTokenFound = True
        # regex value arcs
        if dToken["sType"] not in frozenset(["INFO", "PUNC", "SIGN"]):
            if "<re_value>" in dNode:
                for sRegex in dNode["<re_value>"]:
                    if "¬" not in sRegex:
                        # no anti-pattern
                        if re.search(sRegex, dToken["sValue"]):
                            if bDebug:
                                echo("  MATCH: ~" + sRegex)
                            yield { "iNode1": iNode1, "dNode": dGraph[dNode["<re_value>"][sRegex]] }
                            bTokenFound = True
                    else:
                        # there is an anti-pattern
                        sPattern, sNegPattern = sRegex.split("¬", 1)




                        if sNegPattern and re.search(sNegPattern, dToken["sValue"]):
                            continue
                        if not sPattern or re.search(sPattern, dToken["sValue"]):
                            if bDebug:
                                echo("  MATCH: ~" + sRegex)
                            yield { "iNode1": iNode1, "dNode": dGraph[dNode["<re_value>"][sRegex]] }
                            bTokenFound = True
        # analysable tokens
        if dToken["sType"][0:4] == "WORD":
            # token lemmas
            if "<lemmas>" in dNode:
                for sLemma in _oSpellChecker.getLemma(dToken["sValue"]):
                    if sLemma in dNode["<lemmas>"]:
                        if bDebug:
                            echo("  MATCH: >" + sLemma)
                        yield { "iNode1": iNode1, "dNode": dGraph[dNode["<lemmas>"][sLemma]] }
                        bTokenFound = True
            # regex morph arcs
            if "<re_morph>" in dNode:
                lMorph = dToken.get("lMorph", _oSpellChecker.getMorph(dToken["sValue"]))
                for sRegex in dNode["<re_morph>"]:
                    if "¬" not in sRegex:
                        # no anti-pattern
                        if any(re.search(sRegex, sMorph)  for sMorph in lMorph):
                            if bDebug:
                                echo("  MATCH: @" + sRegex)
                            yield { "iNode1": iNode1, "dNode": dGraph[dNode["<re_morph>"][sRegex]] }
                            bTokenFound = True
                    else:


                        # there is an anti-pattern
                        sPattern, sNegPattern = sRegex.split("¬", 1)
                        if sNegPattern == "*":


                            # all morphologies must match with <sPattern>
                            if sPattern:


                                if lMorph and all(re.search(sPattern, sMorph)  for sMorph in lMorph):
                                    if bDebug:
                                        echo("  MATCH: @" + sRegex)
                                    yield { "iNode1": iNode1, "dNode": dGraph[dNode["<re_morph>"][sRegex]] }
                                    bTokenFound = True
                        else:
                            if sNegPattern and any(re.search(sNegPattern, sMorph)  for sMorph in lMorph):
                                continue
                            if not sPattern or any(re.search(sPattern, sMorph)  for sMorph in lMorph):
                                if bDebug:
                                    echo("  MATCH: @" + sRegex)
                                yield { "iNode1": iNode1, "dNode": dGraph[dNode["<re_morph>"][sRegex]] }
                                bTokenFound = True
        # token tags
        if "tags" in dToken and "<tags>" in dNode:
            for sTag in dToken["tags"]:
                if sTag in dNode["<tags>"]:
                    if bDebug:
                        echo("  MATCH: /" + sTag)
                    yield { "iNode1": iNode1, "dNode": dGraph[dNode["<tags>"][sTag]] }
                    bTokenFound = True
        # meta arc (for token type)
        if "<meta>" in dNode:
            for sMeta in dNode["<meta>"]:
                # no regex here, we just search if <dNode["sType"]> exists within <sMeta>
                if sMeta == "*" or dToken["sType"] == sMeta:
                    if bDebug:
                        echo("  MATCH: *" + sMeta)
                    yield { "iNode1": iNode1, "dNode": dGraph[dNode["<meta>"][sMeta]] }
                    bTokenFound = True
                elif "¬" in sMeta:
                    if dToken["sType"] not in sMeta:
                        if bDebug:
                            echo("  MATCH: *" + sMeta)
                        yield { "iNode1": iNode1, "dNode": dGraph[dNode["<meta>"][sMeta]] }
                        bTokenFound = True
        if not bTokenFound and "bKeep" in dPointer:
            yield dPointer
        # JUMP
        # Warning! Recurssion!
        if "<>" in dNode:
            dPointer2 = { "iNode1": iNode1, "dNode": dGraph[dNode["<>"]], "bKeep": True }
            yield from self._getNextPointers(dToken, dGraph, dPointer2, bDebug)

    def parseGraph (self, dGraph, sCountry="${country_default}", dOptions=None, bShowRuleId=False, bDebug=False, bContext=False):
        "parse graph with tokens from the text and execute actions encountered"
        lPointer = []
        bTagAndRewrite = False
        for iToken, dToken in enumerate(self.lToken):
            if bDebug:
                echo("TOKEN: " + dToken["sValue"])
            # check arcs for each existing pointer
            lNextPointer = []
            for dPointer in lPointer:
                lNextPointer.extend(self._getNextPointers(dToken, dGraph, dPointer, bDebug))
            lPointer = lNextPointer
            # check arcs of first nodes
            lPointer.extend(self._getNextPointers(dToken, dGraph, { "iNode1": iToken, "dNode": dGraph[0] }, bDebug))
            # check if there is rules to check for each pointer
            for dPointer in lPointer:
                #if bDebug:
                #    echo("+", dPointer)
                if "<rules>" in dPointer["dNode"]:
                    bChange = self._executeActions(dGraph, dPointer["dNode"]["<rules>"], dPointer["iNode1"]-1, iToken, dOptions, sCountry, bShowRuleId, bDebug, bContext)
                    if bChange:
                        bTagAndRewrite = True
        if bTagAndRewrite:
            self.rewriteFromTags(bDebug)
        if bDebug:
            echo(self)
        return self.sSentence




    def _executeActions (self, dGraph, dNode, nTokenOffset, nLastToken, dOptions, sCountry, bShowRuleId, bDebug, bContext):
        "execute actions found in the DARG"
        bChange = False

        for sLineId, nextNodeKey in dNode.items():
            bCondMemo = None
            for sRuleId in dGraph[nextNodeKey]:
                try:
                    if bDebug:
                        echo("   >TRY: " + sRuleId + " " + sLineId)
                    sOption, sFuncCond, cActionType, sWhat, *eAct = _rules_graph.dRule[sRuleId]
                    # Suggestion    [ option, condition, "-", replacement/suggestion/action, iTokenStart, iTokenEnd, cStartLimit, cEndLimit, bCaseSvty, nPriority, sMessage, sURL ]
                    # TextProcessor [ option, condition, "~", replacement/suggestion/action, iTokenStart, iTokenEnd, bCaseSvty ]
                    # Disambiguator [ option, condition, "=", replacement/suggestion/action ]
                    # Tag           [ option, condition, "/", replacement/suggestion/action, iTokenStart, iTokenEnd ]
                    # Immunity      [ option, condition, "%", "",                            iTokenStart, iTokenEnd ]
                    # Test          [ option, condition, ">", "" ]
                    if not sOption or dOptions.get(sOption, False):
                        bCondMemo = not sFuncCond or globals()[sFuncCond](self.lToken, nTokenOffset, nLastToken, sCountry, bCondMemo, self.dTags, self.sSentence, self.sSentence0)
                        if bCondMemo:
                            if cActionType == "-":
                                # grammar error
                                iTokenStart, iTokenEnd, cStartLimit, cEndLimit, bCaseSvty, nPriority, sMessage, sURL = eAct
                                nTokenErrorStart = nTokenOffset + iTokenStart  if iTokenStart > 0  else nLastToken + iTokenStart
                                if "bImmune" not in self.lToken[nTokenErrorStart]:
                                    nTokenErrorEnd = nTokenOffset + iTokenEnd  if iTokenEnd > 0  else nLastToken + iTokenEnd
                                    nErrorStart = self.nOffsetWithinParagraph + (self.lToken[nTokenErrorStart]["nStart"] if cStartLimit == "<"  else self.lToken[nTokenErrorStart]["nEnd"])
                                    nErrorEnd = self.nOffsetWithinParagraph + (self.lToken[nTokenErrorEnd]["nEnd"] if cEndLimit == ">"  else self.lToken[nTokenErrorEnd]["nStart"])
                                    if nErrorStart not in self.dError or nPriority > self.dErrorPriority.get(nErrorStart, -1):
                                        self.dError[nErrorStart] = self._createErrorFromTokens(sWhat, nTokenOffset, nLastToken, nTokenErrorStart, nErrorStart, nErrorEnd, sLineId, sRuleId, bCaseSvty, sMessage, sURL, bShowRuleId, sOption, bContext)
                                        self.dErrorPriority[nErrorStart] = nPriority
                                        if bDebug:
                                            echo("    NEW_ERROR: {}".format(self.dError[nErrorStart]))
                            elif cActionType == "~":
                                # text processor
                                nTokenStart = nTokenOffset + eAct[0]  if eAct[0] > 0  else nLastToken + eAct[0]
                                nTokenEnd = nTokenOffset + eAct[1]  if eAct[1] > 0  else nLastToken + eAct[1]
                                self._tagAndPrepareTokenForRewriting(sWhat, nTokenStart, nTokenEnd, nTokenOffset, nLastToken, eAct[2], bDebug)
                                bChange = True
                                if bDebug:
                                    echo("    TEXT_PROCESSOR: [{}:{}]  > {}".format(self.lToken[nTokenStart]["sValue"], self.lToken[nTokenEnd]["sValue"], sWhat))
                            elif cActionType == "=":
                                # disambiguation
                                globals()[sWhat](self.lToken, nTokenOffset, nLastToken)
                                if bDebug:
                                    echo("    DISAMBIGUATOR: ({})  [{}:{}]".format(sWhat, self.lToken[nTokenOffset+1]["sValue"], self.lToken[nLastToken]["sValue"]))
                            elif cActionType == ">":
                                # we do nothing, this test is just a condition to apply all following actions
                                if bDebug:
                                    echo("    COND_OK")
                                pass
                            elif cActionType == "/":
                                # Tag
                                nTokenStart = nTokenOffset + eAct[0]  if eAct[0] > 0  else nLastToken + eAct[0]
                                nTokenEnd = nTokenOffset + eAct[1]  if eAct[1] > 0  else nLastToken + eAct[1]
                                for i in range(nTokenStart, nTokenEnd+1):
                                    if "tags" in self.lToken[i]:
                                        self.lToken[i]["tags"].update(sWhat.split("|"))
                                    else:
                                        self.lToken[i]["tags"] = set(sWhat.split("|"))
                                if bDebug:
                                    echo("    TAG: {} >  [{}:{}]".format(sWhat, self.lToken[nTokenStart]["sValue"], self.lToken[nTokenEnd]["sValue"]))
                                if sWhat not in self.dTags:
                                    self.dTags[sWhat] = [nTokenStart, nTokenStart]
                                else:
                                    self.dTags[sWhat][0] = min(nTokenStart, self.dTags[sWhat][0])
                                    self.dTags[sWhat][1] = max(nTokenEnd, self.dTags[sWhat][1])
                            elif cActionType == "%":
                                # immunity
                                if bDebug:
                                    echo("    IMMUNITY: " + _rules_graph.dRule[sRuleId])
                                nTokenStart = nTokenOffset + eAct[0]  if eAct[0] > 0  else nLastToken + eAct[0]
                                nTokenEnd = nTokenOffset + eAct[1]  if eAct[1] > 0  else nLastToken + eAct[1]
                                if nTokenEnd - nTokenStart == 0:
                                    self.lToken[nTokenStart]["bImmune"] = True
                                    nErrorStart = self.nOffsetWithinParagraph + self.lToken[nTokenStart]["nStart"]
                                    if nErrorStart in self.dError:
                                        del self.dError[nErrorStart]
                                else:
                                    for i in range(nTokenStart, nTokenEnd+1):
                                        self.lToken[i]["bImmune"] = True
                                        nErrorStart = self.nOffsetWithinParagraph + self.lToken[i]["nStart"]
                                        if nErrorStart in self.dError:
                                            del self.dError[nErrorStart]
                            else:
                                echo("# error: unknown action at " + sLineId)
                        elif cActionType == ">":
                            if bDebug:
                                echo("    COND_BREAK")
                            break
                except Exception as e:
                    raise Exception(str(e), sLineId, sRuleId, self.sSentence)
        return bChange


    def _createErrorFromRegex (self, sText, sText0, sRepl, nOffset, m, iGroup, sLineId, sRuleId, bUppercase, sMsg, sURL, bShowRuleId, sOption, bContext):
        nStart = nOffset + m.start(iGroup)
        nEnd = nOffset + m.end(iGroup)
        # suggestions
        if sRepl[0:1] == "=":
            sSugg = globals()[sRepl[1:]](sText, m)
            lSugg = sSugg.split("|")  if sSugg  else []
        elif sRepl == "_":
            lSugg = []
        else:
            lSugg = m.expand(sRepl).split("|")
        if bUppercase and lSugg and m.group(iGroup)[0:1].isupper():
            lSugg = list(map(str.capitalize, lSugg))
        # Message
        sMessage = globals()[sMsg[1:]](sText, m)  if sMsg[0:1] == "="  else  m.expand(sMsg)
        if bShowRuleId:


            sMessage += "  # " + sLineId + " # " + sRuleId
        #
        if _bWriterError:
            return self._createErrorForWriter(nStart, nEnd - nStart, sRuleId, sMessage, lSugg, sURL)
        else:
            return self._createErrorAsDict(nStart, nEnd, sLineId, sRuleId, sOption, sMessage, lSugg, sURL, bContext)




    def _createErrorFromTokens (self, sSugg, nTokenOffset, nLastToken, iFirstToken, nStart, nEnd, sLineId, sRuleId, bCaseSvty, sMsg, sURL, bShowRuleId, sOption, bContext):
        # suggestions
        if sSugg[0:1] == "=":
            sSugg = globals()[sSugg[1:]](self.lToken, nTokenOffset, nLastToken)
            lSugg = sSugg.split("|")  if sSugg  else []
        elif sSugg == "_":
            lSugg = []
        else:



            lSugg = self._expand(sSugg, nTokenOffset, nLastToken).split("|")
        if bCaseSvty and lSugg and self.lToken[iFirstToken]["sValue"][0:1].isupper():
            lSugg = list(map(lambda s: s[0:1].upper()+s[1:], lSugg))
        # Message
        sMessage = globals()[sMsg[1:]](self.lToken, nTokenOffset, nLastToken)  if sMsg[0:1] == "="  else self._expand(sMsg, nTokenOffset, nLastToken)
        if bShowRuleId:
            sMessage += "  " + sLineId + " # " + sRuleId
        #
        if _bWriterError:
            return self._createErrorForWriter(nStart, nEnd - nStart, sRuleId, sMessage, lSugg, sURL)
        else:
            return self._createErrorAsDict(nStart, nEnd, sLineId, sRuleId, sOption, sMessage, lSugg, sURL, bContext)

    def _createErrorForWriter (self, nStart, nLen, sRuleId, sMessage, lSugg, sURL):
        xErr = SingleProofreadingError()    # uno.createUnoStruct( "com.sun.star.linguistic2.SingleProofreadingError" )
        xErr.nErrorStart = nStart
        xErr.nErrorLength = nLen
        xErr.nErrorType = PROOFREADING
        xErr.aRuleIdentifier = sRuleId
        xErr.aShortComment = sMessage   # sMessage.split("|")[0]     # in context menu
        xErr.aFullComment = sMessage    # sMessage.split("|")[-1]    # in dialog
        xErr.aSuggestions = tuple(lSugg)
        #xPropertyLineType = PropertyValue(Name="LineType", Value=5) # DASH or WAVE
        #xPropertyLineColor = PropertyValue(Name="LineColor", Value=getRGB("FFAA00"))
        if sURL:
            xPropertyURL = PropertyValue(Name="FullCommentURL", Value=sURL)
            xErr.aProperties = (xPropertyURL,)
        else:
            xErr.aProperties = ()
        return xErr




    def _createErrorAsDict (self, nStart, nEnd, sLineId, sRuleId, sOption, sMessage, lSugg, sURL, bContext):
        dErr = {
            "nStart": nStart,
            "nEnd": nEnd,
            "sLineId": sLineId,
            "sRuleId": sRuleId,
            "sType": sOption  if sOption  else "notype",
            "sMessage": sMessage,
            "aSuggestions": lSugg,
            "URL": sURL
        }



        if bContext:
            dErr['sUnderlined'] = self.sText0[nStart:nEnd]
            dErr['sBefore'] = self.sText0[max(0,nStart-80):nStart]
            dErr['sAfter'] = self.sText0[nEnd:nEnd+80]
        return dErr


    def _expand (self, sText, nTokenOffset, nLastToken):
        for m in re.finditer(r"\\(-?[0-9]+)", sText):
            if m.group(1)[0:1] == "-":
                sText = sText.replace(m.group(0), self.lToken[nLastToken+int(m.group(1))+1]["sValue"])
            else:
                sText = sText.replace(m.group(0), self.lToken[nTokenOffset+int(m.group(1))]["sValue"])
        return sText

    def rewriteText (self, sText, sRepl, iGroup, m, bUppercase):
        "text processor: write <sRepl> in <sText> at <iGroup> position"
        nLen = m.end(iGroup) - m.start(iGroup)
        if sRepl == "*":
            sNew = " " * nLen
        elif sRepl == "_":
            sNew = sRepl + " " * (nLen-1)
        elif sRepl[0:1] == "=":
            sNew = globals()[sRepl[1:]](sText, m)
            sNew = sNew + " " * (nLen-len(sNew))
            if bUppercase and m.group(iGroup)[0:1].isupper():
                sNew = sNew.capitalize()
        else:
            sNew = m.expand(sRepl)
            sNew = sNew + " " * (nLen-len(sNew))
        return sText[0:m.start(iGroup)] + sNew + sText[m.end(iGroup):]

    def _tagAndPrepareTokenForRewriting (self, sWhat, nTokenRewriteStart, nTokenRewriteEnd, nTokenOffset, nLastToken, bCaseSvty, bDebug):
        "text processor: rewrite tokens between <nTokenRewriteStart> and <nTokenRewriteEnd> position"
        if sWhat == "*":
            # purge text
            if nTokenRewriteEnd - nTokenRewriteStart == 0:
                self.lToken[nTokenRewriteStart]["bToRemove"] = True
            else:
                for i in range(nTokenRewriteStart, nTokenRewriteEnd+1):
                    self.lToken[i]["bToRemove"] = True
        elif sWhat == "␣":
            # merge tokens
            self.lToken[nTokenRewriteStart]["nMergeUntil"] = nTokenRewriteEnd
        elif sWhat == "_":
            # neutralized token
            if nTokenRewriteEnd - nTokenRewriteStart == 0:
                self.lToken[nTokenRewriteStart]["sNewValue"] = "_"
            else:
                for i in range(nTokenRewriteStart, nTokenRewriteEnd+1):
                    self.lToken[i]["sNewValue"] = "_"
        else:
            if sWhat.startswith("="):
                sWhat = globals()[sWhat[1:]](self.lToken, nTokenOffset, nLastToken)
            else:
                sWhat = self._expand(sWhat, nTokenOffset, nLastToken)
            bUppercase = bCaseSvty and self.lToken[nTokenRewriteStart]["sValue"][0:1].isupper()
            if nTokenRewriteEnd - nTokenRewriteStart == 0:
                # one token
                if bUppercase:
                    sWhat = sWhat[0:1].upper() + sWhat[1:]
                self.lToken[nTokenRewriteStart]["sNewValue"] = sWhat
            else:
                # several tokens
                lTokenValue = sWhat.split("|")
                if len(lTokenValue) != (nTokenRewriteEnd - nTokenRewriteStart + 1):
                    echo("Error. Text processor: number of replacements != number of tokens.")
                    return

                for i, sValue in zip(range(nTokenRewriteStart, nTokenRewriteEnd+1), lTokenValue):
                    if not sValue or sValue == "*":
                        self.lToken[i]["bToRemove"] = True
                    else:
                        if bUppercase:
                            sValue = sValue[0:1].upper() + sValue[1:]
                        self.lToken[i]["sNewValue"] = sValue

    def rewriteFromTags (self, bDebug=False):
        "rewrite the sentence, modify tokens, purge the token list"
        if bDebug:
            echo("REWRITE")
        lNewToken = []
        nMergeUntil = 0
        dTokenMerger = None
        for iToken, dToken in enumerate(self.lToken):
            bKeepToken = True
            if dToken["sType"] != "INFO":
                if nMergeUntil and iToken <= nMergeUntil:
                    dTokenMerger["sValue"] += " " * (dToken["nStart"] - dTokenMerger["nEnd"]) + dToken["sValue"]
                    dTokenMerger["nEnd"] = dToken["nEnd"]
                    if bDebug:
                        echo("  MERGED TOKEN: " + dTokenMerger["sValue"])
                    bKeepToken = False
                if "nMergeUntil" in dToken:
                    if iToken > nMergeUntil: # this token is not already merged with a previous token
                        dTokenMerger = dToken
                    if dToken["nMergeUntil"] > nMergeUntil:
                        nMergeUntil = dToken["nMergeUntil"]
                    del dToken["nMergeUntil"]
                elif "bToRemove" in dToken:
                    if bDebug:
                        echo("  REMOVED: " + dToken["sValue"])
                    self.sSentence = self.sSentence[:dToken["nStart"]] + " " * (dToken["nEnd"] - dToken["nStart"]) + self.sSentence[dToken["nEnd"]:]
                    bKeepToken = False
            #
            if bKeepToken:
                lNewToken.append(dToken)
                if "sNewValue" in dToken:
                    # rewrite token and sentence
                    if bDebug:
                        echo(dToken["sValue"] + " -> " + dToken["sNewValue"])
                    dToken["sRealValue"] = dToken["sValue"]
                    dToken["sValue"] = dToken["sNewValue"]
                    nDiffLen = len(dToken["sRealValue"]) - len(dToken["sNewValue"])
                    sNewRepl = (dToken["sNewValue"] + " " * nDiffLen)  if nDiffLen >= 0  else dToken["sNewValue"][:len(dToken["sRealValue"])]
                    self.sSentence = self.sSentence[:dToken["nStart"]] + sNewRepl + self.sSentence[dToken["nEnd"]:]
                    del dToken["sNewValue"]
            else:
                try:
                    del self.dTokenPos[dToken["nStart"]]
                except:
                    echo(self)
                    echo(dToken)
                    exit()
        if bDebug:
            echo("  TEXT REWRITED: " + self.sSentence)
        self.lToken.clear()
        self.lToken = lNewToken


#### common functions

def option (sOpt):
    "return True if option <sOpt> is active"
    return _dOptions.get(sOpt, False)


#### Functions to get text outside pattern scope

# warning: check compile_rules.py to understand how it works

_zNextWord = re.compile(r" +(\w[\w-]*)")
_zPrevWord = re.compile(r"(\w[\w-]*) +$")

def nextword (s, iStart, n):
    "get the nth word of the input string or empty string"
    m = re.match("(?: +[\\w%-]+){" + str(n-1) + "} +([\\w%-]+)", s[iStart:])
    if not m:
        return None
    return (iStart+m.start(1), m.group(1))

................................................................................
    if sNegPattern and re.search(sNegPattern, s):
        return False
    if re.search(sPattern, s):
        return True
    return False


def look_chk1 (dTokenPos, s, nOffset, sPattern, sPatternGroup1, sNegPatternGroup1=""):
    "returns True if s has pattern sPattern and m.group(1) has pattern sPatternGroup1"
    m = re.search(sPattern, s)
    if not m:
        return False
    try:
        sWord = m.group(1)
        nPos = m.start(1) + nOffset
    except:
        return False
    return morph(dTokenPos, (nPos, sWord), sPatternGroup1, sNegPatternGroup1)



#### Analyse groups for regex rules

def displayInfo (dTokenPos, tWord):
    "for debugging: retrieve info of word"
    if not tWord:
        echo("> nothing to find")
        return True
    lMorph = _oSpellChecker.getMorph(tWord[1])
    if not lMorph:
        echo("> not in dictionary")
        return True
    echo("TOKENS:", dTokenPos)
    if tWord[0] in dTokenPos and "lMorph" in dTokenPos[tWord[0]]:
        echo("DA: " + str(dTokenPos[tWord[0]]["lMorph"]))
    echo("FSA: " + str(lMorph))
    return True


def morph (dTokenPos, tWord, sPattern, sNegPattern="", bNoWord=False):
    "analyse a tuple (position, word), returns True if not sNegPattern in word morphologies and sPattern in word morphologies (disambiguation on)"
    if not tWord:
        return bNoWord
    lMorph = dTokenPos[tWord[0]]["lMorph"]  if tWord[0] in dTokenPos and "lMorph" in dTokenPos[tWord[0]]  else _oSpellChecker.getMorph(tWord[1])
    if not lMorph:
        return False
    # check negative condition
    if sNegPattern:


        if sNegPattern == "*":
            # all morph must match sPattern
            zPattern = re.compile(sPattern)
            return all(zPattern.search(sMorph)  for sMorph in lMorph)
        else:
            zNegPattern = re.compile(sNegPattern)
            if any(zNegPattern.search(sMorph)  for sMorph in lMorph):
                return False
    # search sPattern
    zPattern = re.compile(sPattern)
    return any(zPattern.search(sMorph)  for sMorph in lMorph)


def analyse (sWord, sPattern, sNegPattern=""):
    "analyse a word, returns True if not sNegPattern in word morphologies and sPattern in word morphologies (disambiguation off)"
    lMorph = _oSpellChecker.getMorph(sWord)
    if not lMorph:
        return False
    # check negative condition
    if sNegPattern:
        if sNegPattern == "*":
            zPattern = re.compile(sPattern)
            return all(zPattern.search(sMorph)  for sMorph in lMorph)
        else:
            zNegPattern = re.compile(sNegPattern)
            if any(zNegPattern.search(sMorph)  for sMorph in lMorph):
                return False
    # search sPattern
    zPattern = re.compile(sPattern)
    return any(zPattern.search(sMorph)  for sMorph in lMorph)


#### Analyse tokens for graph rules

def g_value (dToken, sValues, nLeft=None, nRight=None):
    "test if <dToken['sValue']> is in sValues (each value should be separated with |)"
    sValue = "|"+dToken["sValue"]+"|"  if nLeft is None  else "|"+dToken["sValue"][slice(nLeft, nRight)]+"|"
    if sValue in sValues:
        return True
    if dToken["sValue"][0:2].istitle(): # we test only 2 first chars, to make valid words such as "Laissez-les", "Passe-partout".
        if sValue.lower() in sValues:
            return True
    elif dToken["sValue"].isupper():
        #if sValue.lower() in sValues:
        #    return True
        sValue = "|"+sValue[1:].capitalize()
        if sValue in sValues:
            return True
    return False


def g_morph (dToken, sPattern, sNegPattern="", nLeft=None, nRight=None, bMemorizeMorph=True):
    "analyse a token, return True if <sNegPattern> not in morphologies and <sPattern> in morphologies"
    if "lMorph" in dToken:
        lMorph = dToken["lMorph"]
    else:
        if nLeft is not None:
            lMorph = _oSpellChecker.getMorph(dToken["sValue"][slice(nLeft, nRight)])
            if bMemorizeMorph:
                dToken["lMorph"] = lMorph
        else:
            lMorph = _oSpellChecker.getMorph(dToken["sValue"])
    if not lMorph:
        return False
    # check negative condition
    if sNegPattern:
        if sNegPattern == "*":
            # all morph must match sPattern
            zPattern = re.compile(sPattern)
            return all(zPattern.search(sMorph)  for sMorph in lMorph)
        else:
            zNegPattern = re.compile(sNegPattern)
            if any(zNegPattern.search(sMorph)  for sMorph in lMorph):
                return False
    # search sPattern
    zPattern = re.compile(sPattern)
    return any(zPattern.search(sMorph)  for sMorph in lMorph)


def g_analyse (dToken, sPattern, sNegPattern="", nLeft=None, nRight=None, bMemorizeMorph=True):
    "analyse a token, return True if <sNegPattern> not in morphologies and <sPattern> in morphologies (disambiguation off)"
    if nLeft is not None:
        lMorph = _oSpellChecker.getMorph(dToken["sValue"][slice(nLeft, nRight)])
        if bMemorizeMorph:
            dToken["lMorph"] = lMorph
    else:
        lMorph = _oSpellChecker.getMorph(dToken["sValue"])
    if not lMorph:
        return False
    # check negative condition
    if sNegPattern:
        if sNegPattern == "*":
            # all morph must match sPattern
            zPattern = re.compile(sPattern)
            return all(zPattern.search(sMorph)  for sMorph in lMorph)
        else:
            zNegPattern = re.compile(sNegPattern)
            if any(zNegPattern.search(sMorph)  for sMorph in lMorph):
                return False
    # search sPattern
    zPattern = re.compile(sPattern)
    return any(zPattern.search(sMorph)  for sMorph in lMorph)


def g_merged_analyse (dToken1, dToken2, cMerger, sPattern, sNegPattern="", bSetMorph=True):
    "merge two token values, return True if <sNegPattern> not in morphologies and <sPattern> in morphologies (disambiguation off)"
    lMorph = _oSpellChecker.getMorph(dToken1["sValue"] + cMerger + dToken2["sValue"])
    if not lMorph:
        return False
    # check negative condition
    if sNegPattern:
        if sNegPattern == "*":
            # all morph must match sPattern
            zPattern = re.compile(sPattern)
            bResult = all(zPattern.search(sMorph)  for sMorph in lMorph)
            if bResult and bSetMorph:
                dToken1["lMorph"] = lMorph
            return bResult
        else:
            zNegPattern = re.compile(sNegPattern)
            if any(zNegPattern.search(sMorph)  for sMorph in lMorph):
                return False
    # search sPattern
    zPattern = re.compile(sPattern)
    bResult = any(zPattern.search(sMorph)  for sMorph in lMorph)
    if bResult and bSetMorph:
        dToken1["lMorph"] = lMorph
    return bResult


def g_tag_before (dToken, dTags, sTag):
    if sTag not in dTags:
        return False
    if dToken["i"] > dTags[sTag][0]:
        return True
    return False


def g_tag_after (dToken, dTags, sTag):
    if sTag not in dTags:
        return False
    if dToken["i"] < dTags[sTag][1]:
        return True
    return False


def g_tag (dToken, sTag):
    return "tags" in dToken and sTag in dToken["tags"]


def g_space_between_tokens (dToken1, dToken2, nMin, nMax=None):
    nSpace = dToken2["nStart"] - dToken1["nEnd"]
    if nSpace < nMin:
        return False
    if nMax is not None and nSpace > nMax:
        return False
    return True


def g_token (lToken, i):
    if i < 0:
        return lToken[0]
    if i >= len(lToken):
        return lToken[-1]
    return lToken[i]



#### Disambiguator for regex rules

def select (dTokenPos, nPos, sWord, sPattern, lDefault=None):
    "Disambiguation: select morphologies of <sWord> matching <sPattern>"
    if not sWord:
        return True
    if nPos not in dTokenPos:
        echo("Error. There should be a token at this position: ", nPos)
        return True

    lMorph = _oSpellChecker.getMorph(sWord)
    if not lMorph or len(lMorph) == 1:
        return True


    lSelect = [ sMorph  for sMorph in lMorph  if re.search(sPattern, sMorph) ]
    if lSelect:
        if len(lSelect) != len(lMorph):
            dTokenPos[nPos]["lMorph"] = lSelect

    elif lDefault:
        dTokenPos[nPos]["lMorph"] = lDefault

    return True


def exclude (dTokenPos, nPos, sWord, sPattern, lDefault=None):
    "Disambiguation: exclude morphologies of <sWord> matching <sPattern>"
    if not sWord:
        return True
    if nPos not in dTokenPos:
        echo("Error. There should be a token at this position: ", nPos)
        return True

    lMorph = _oSpellChecker.getMorph(sWord)
    if not lMorph or len(lMorph) == 1:
        return True

    lSelect = [ sMorph  for sMorph in lMorph  if not re.search(sPattern, sMorph) ]
    if lSelect:
        if len(lSelect) != len(lMorph):
            dTokenPos[nPos]["lMorph"] = lSelect
    elif lDefault:
        dTokenPos[nPos]["lMorph"] = lDefault
    return True


def define (dTokenPos, nPos, lMorph):
    "Disambiguation: set morphologies of token at <nPos> with <lMorph>"
    if nPos not in dTokenPos:
        echo("Error. There should be a token at this position: ", nPos)
        return True
    dTokenPos[nPos]["lMorph"] = lMorph
    return True


#### Disambiguation for graph rules

def g_select (dToken, sPattern, lDefault=None):
    "select morphologies for <dToken> according to <sPattern>, always return True"
    lMorph = dToken["lMorph"]  if "lMorph" in dToken  else _oSpellChecker.getMorph(dToken["sValue"])
    if not lMorph or len(lMorph) == 1:
        if lDefault:
            dToken["lMorph"] = lDefault
            #echo("DA:", dToken["sValue"], dToken["lMorph"])
        return True
    lSelect = [ sMorph  for sMorph in lMorph  if re.search(sPattern, sMorph) ]
    if lSelect:
        if len(lSelect) != len(lMorph):
            dToken["lMorph"] = lSelect

    elif lDefault:
        dToken["lMorph"] = lDefault
    #echo("DA:", dToken["sValue"], dToken["lMorph"])
    return True


def g_exclude (dToken, sPattern, lDefault=None):
    "select morphologies for <dToken> according to <sPattern>, always return True"
    lMorph = dToken["lMorph"]  if "lMorph" in dToken  else _oSpellChecker.getMorph(dToken["sValue"])
    if not lMorph or len(lMorph) == 1:
        if lDefault:

            dToken["lMorph"] = lDefault
            #echo("DA:", dToken["sValue"], dToken["lMorph"])
        return True
    lSelect = [ sMorph  for sMorph in lMorph  if not re.search(sPattern, sMorph) ]
    if lSelect:
        if len(lSelect) != len(lMorph):
            dToken["lMorph"] = lSelect
    elif lDefault:
        dToken["lMorph"] = lDefault
    #echo("DA:", dToken["sValue"], dToken["lMorph"])
    return True



def g_define (dToken, lMorph):
    "set morphologies of <dToken>, always return True"
    dToken["lMorph"] = lMorph

    #echo("DA:", dToken["sValue"], lMorph)
    return True


def g_define_from (dToken, nLeft=None, nRight=None):
    if nLeft is not None:
        dToken["lMorph"] = _oSpellChecker.getMorph(dToken["sValue"][slice(nLeft, nRight)])
    else:
        dToken["lMorph"] = _oSpellChecker.getMorph(dToken["sValue"])
    return True



#### GRAMMAR CHECKER PLUGINS

${plugins}


#### CALLABLES FOR REGEX RULES (generated code)

${callables}


#### CALLABLES FOR GRAPH RULES (generated code)

${graph_callables}

Modified gc_core/py/lang_core/gc_options.py from [871c8d4b8f] to [c84731594a].





1
2
3

4
5
6
7
8
9

10
11
12
13
14
15
16




# generated code, do not edit

def getUI (sLang):

    if sLang in _dOptLabel:
        return _dOptLabel[sLang]
    return _dOptLabel["fr"]


def getOptions (sContext="Python"):

    if sContext in dOpt:
        return dOpt[sContext]
    return dOpt["Python"]


lStructOpt = ${lStructOpt}

>
>
>
>



>






>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
"""
Grammar checker default options
"""

# generated code, do not edit

def getUI (sLang):
    "returns dictionary of UI labels"
    if sLang in _dOptLabel:
        return _dOptLabel[sLang]
    return _dOptLabel["fr"]


def getOptions (sContext="Python"):
    "returns dictionary of options"
    if sContext in dOpt:
        return dOpt[sContext]
    return dOpt["Python"]


lStructOpt = ${lStructOpt}

Modified gc_core/py/lang_core/gc_rules.py from [3cf95f4a21] to [2ef08593b5].





1
2
3
4
5




# generated code, do not edit

lParagraphRules = ${paragraph_rules}

lSentenceRules = ${sentence_rules}
>
>
>
>





1
2
3
4
5
6
7
8
9
"""
Grammar checker regex rules
"""

# generated code, do not edit

lParagraphRules = ${paragraph_rules}

lSentenceRules = ${sentence_rules}

Added gc_core/py/lang_core/gc_rules_graph.py version [373592f3fb].



















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
"""
Grammar checker graph rules
"""

# generated code, do not edit

dAllGraph = ${rules_graphs}

dRule = ${rules_actions}

Modified gc_core/py/text.py from [133d154e72] to [137c7cc30f].

1




2
3
4
5
6
7
8
..
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
..
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
..
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!python3





import textwrap
from itertools import chain


def getParagraph (sText):
    "generator: returns paragraphs of text"
................................................................................
        return ""
    lGrammErrs = sorted(aGrammErrs, key=lambda d: d["nStart"])
    lSpellErrs = sorted(aSpellErrs, key=lambda d: d['nStart'])
    sText = ""
    nOffset = 0
    for sLine in wrap(sParagraph, nWidth): # textwrap.wrap(sParagraph, nWidth, drop_whitespace=False)
        sText += sLine + "\n"
        ln = len(sLine)
        sErrLine = ""
        nLenErrLine = 0
        nGrammErr = 0
        nSpellErr = 0
        for dErr in lGrammErrs:
            nStart = dErr["nStart"] - nOffset
            if nStart < ln:
                nGrammErr += 1
                if nStart >= nLenErrLine:
                    sErrLine += " " * (nStart - nLenErrLine) + "^" * (dErr["nEnd"] - dErr["nStart"])
                    nLenErrLine = len(sErrLine)
            else:
                break
        for dErr in lSpellErrs:
            nStart = dErr['nStart'] - nOffset
            if nStart < ln:
                nSpellErr += 1
                nEnd = dErr['nEnd'] - nOffset
                if nEnd > len(sErrLine):
                    sErrLine += " " * (nEnd - len(sErrLine))
                sErrLine = sErrLine[:nStart] + "°" * (nEnd - nStart) + sErrLine[nEnd:]
            else:
                break
................................................................................
            sText += sErrLine + "\n"
        if nGrammErr:
            sText += getReadableErrors(lGrammErrs[:nGrammErr], nWidth)
            del lGrammErrs[0:nGrammErr]
        if nSpellErr:
            sText += getReadableErrors(lSpellErrs[:nSpellErr], nWidth, True)
            del lSpellErrs[0:nSpellErr]
        nOffset += ln
    return sText


def getReadableErrors (lErrs, nWidth, bSpell=False):
    "Returns lErrs errors as readable errors"
    sErrors = ""
    for dErr in lErrs:
................................................................................
    return sErrors


def getReadableError (dErr, bSpell=False):
    "Returns an error dErr as a readable error"
    try:
        if bSpell:
            s = u"* {nStart}:{nEnd}  # {sValue}:".format(**dErr)
        else:
            s = u"* {nStart}:{nEnd}  # {sLineId} / {sRuleId}:\n".format(**dErr)
            s += "  " + dErr.get("sMessage", "# error : message not found")
        if dErr.get("aSuggestions", None):
            s += "\n  > Suggestions : " + " | ".join(dErr.get("aSuggestions", "# error : suggestions not found"))
        if dErr.get("URL", None):
            s += "\n  > URL: " + dErr["URL"]
        return s
    except KeyError:
        return u"* Non-compliant error: {}".format(dErr)


def createParagraphWithLines (lLine):
    "Returns a text as merged lines and a set of data about lines (line_number_y, start_x, end_x)"
    sText = ""

>
>
>
>







 







|






|








|







 







|







 







|

|
|

|

|
|







1
2
3
4
5
6
7
8
9
10
11
12
..
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
..
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
..
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!python3

"""
Text tools
"""

import textwrap
from itertools import chain


def getParagraph (sText):
    "generator: returns paragraphs of text"
................................................................................
        return ""
    lGrammErrs = sorted(aGrammErrs, key=lambda d: d["nStart"])
    lSpellErrs = sorted(aSpellErrs, key=lambda d: d['nStart'])
    sText = ""
    nOffset = 0
    for sLine in wrap(sParagraph, nWidth): # textwrap.wrap(sParagraph, nWidth, drop_whitespace=False)
        sText += sLine + "\n"
        nLineLen = len(sLine)
        sErrLine = ""
        nLenErrLine = 0
        nGrammErr = 0
        nSpellErr = 0
        for dErr in lGrammErrs:
            nStart = dErr["nStart"] - nOffset
            if nStart < nLineLen:
                nGrammErr += 1
                if nStart >= nLenErrLine:
                    sErrLine += " " * (nStart - nLenErrLine) + "^" * (dErr["nEnd"] - dErr["nStart"])
                    nLenErrLine = len(sErrLine)
            else:
                break
        for dErr in lSpellErrs:
            nStart = dErr['nStart'] - nOffset
            if nStart < nLineLen:
                nSpellErr += 1
                nEnd = dErr['nEnd'] - nOffset
                if nEnd > len(sErrLine):
                    sErrLine += " " * (nEnd - len(sErrLine))
                sErrLine = sErrLine[:nStart] + "°" * (nEnd - nStart) + sErrLine[nEnd:]
            else:
                break
................................................................................
            sText += sErrLine + "\n"
        if nGrammErr:
            sText += getReadableErrors(lGrammErrs[:nGrammErr], nWidth)
            del lGrammErrs[0:nGrammErr]
        if nSpellErr:
            sText += getReadableErrors(lSpellErrs[:nSpellErr], nWidth, True)
            del lSpellErrs[0:nSpellErr]
        nOffset += nLineLen
    return sText


def getReadableErrors (lErrs, nWidth, bSpell=False):
    "Returns lErrs errors as readable errors"
    sErrors = ""
    for dErr in lErrs:
................................................................................
    return sErrors


def getReadableError (dErr, bSpell=False):
    "Returns an error dErr as a readable error"
    try:
        if bSpell:
            sText = u"* {nStart}:{nEnd}  # {sValue}:".format(**dErr)
        else:
            sText = u"* {nStart}:{nEnd}  # {sLineId} / {sRuleId}:\n".format(**dErr)
            sText += "  " + dErr.get("sMessage", "# error : message not found")
        if dErr.get("aSuggestions", None):
            sText += "\n  > Suggestions : " + " | ".join(dErr.get("aSuggestions", "# error : suggestions not found"))
        if dErr.get("URL", None):
            sText += "\n  > URL: " + dErr["URL"]
        return sText
    except KeyError:
        return u"* Non-compliant error: {}".format(dErr)


def createParagraphWithLines (lLine):
    "Returns a text as merged lines and a set of data about lines (line_number_y, start_x, end_x)"
    sText = ""

Added gc_lang/fr/French_language.txt version [e372ce9fb7].





























































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# NOTES SUR LA LANGUE FRANÇAISE

## CE QUI ENTOURE UN VERBE

    PRONOMS (avant)
        COD         COI
        le / l’
        la / l’
        les
        en
        me / m’     me / m’
        te / t’     te / t’
        se / s’     lui
        nous        nous
        vous        nous
        se / s’     leur
                    y

    SOMME
        [le|la|l’|les|en|me|m’|te|t’|se|s’|nous|vous|lui|leur|y]

    ADVERBE DE NÉGATION (avant)
        ne / n’

    COMBINAISONS VALIDES
        ?[ne|n’]¿   [me|te|se]      [le|la|l’|les]
        ?[ne|n’]¿   [m’|t’|s’]      [le|la|l’|les|en|y]
        ?[ne|n’]¿   [le|la]         [lui|leur]
        ?[ne|n’]¿   [l’|les]        [lui|leur|en|y]
        ?[ne|n’]¿   [lui|leur]      en
        ?[ne|n’]¿   [nous|vous]     [le|la|l’|les|en|y]
        ne          [le|la|l’|les|me|m’|te|t’|se|s’|nous|vous|lui|leur]
        n’          [en|y]

    RÉSUMÉ & SIMPLIFICATION
        [ne|n’|le|la|l’|les|en|me|m’|te|t’|se|s’|nous|vous|lui|leur|y]
        ?[ne|n’]¿   [le|la|l’|les|en|me|m’|te|t’|se|s’|nous|vous|lui|leur|y]
        ?[ne|n’]¿   [me|m’|te|t’|se|s’|nous|vous]   [le|la|l’|les|en|y]
        ?[ne|n’]¿   [le|la|l’|les]                  [lui|leur|en|y]
        ?[ne|n’]¿   [lui|leur]                      en

    ADVERBE DE NÉGATION (après)
        guère
        jamais
        pas
        plus
        point
        que / qu’
        rien

    PRONOMS À L’IMPÉRATIF
        APRÈS
            -moi
            -toi
            -lui
            -leur
            -nous
            -vous
            -le
            -la
            -les
            -en
            -y

        AVANT
            Uniquement les combinaisons avec l’adverbe de négation [ne|n’]


## DÉTERMINANTS

    SINGULIER               PLURIEL
    le / la / l’            les
    ledit / ladite          lesdits / lesdites
    un / une                des
    du / de la              des
    dudit / de ladite       desdits / desdites
    de                      de
    ce / cet / cette        ces
    icelui / icelle         iceux / icelles
    mon / ma                mes
    ton / ta                tes
    son / sa                ses
    votre                   nos
    notre                   vos
    leur                    leurs
    quel / quelle           quels / quelles
    quelque                 quelques
    tout / toute            tous / toutes
    chaque
    aucun / aucune
    nul / nulle
                            plusieurs
                            certains / certaines
                            divers / diverses

    DÉTERMINANT & PRÉPOSITION
    au / à la               aux
    audit / à ladite        auxdits / auxdites


## CONJONCTIONS

    DE COORDINATION         DE SUBORDINATION
    c’est-à-dire            afin que            pendant que
    c.-à-d.                 après que           pour que
    car                     attendu que         pourvu que
    donc                    avant que           puisque
    et / &                  bien que            quand
    mais                    comme               que
    ni                      depuis que          quoique
    or                      dès que             sans que
    ou                      dès lors que        sauf que
    partant                 excepté que         selon que
    puis                    lorsque             si
    sinon                   lors que            tandis que
    soit                    malgré que          tant que
                            parce que


## PRÉPOSITIONS

    VERBALES UNIQUEMENT
        afin de

    NOMINALES ET VERBALES
        à
        entre
        excepté
        outre
        par
        pour
        sans
        sauf

    PRÉPOSITIONS ET DÉTERMINANTS
        au
        aux
        audit
        auxdits
        auxdites

    NOMINALES
        à l’instar de               devers                      par-dessus  (adv)
        à mi-distance de            dixit                       par-devant  (adv)
        après                       durant                      par-devers
        attendu                     dès                         parmi
        au-dedans   (adv)           en                          passé
        au-dehors   (adv)           endéans                     pendant
        au-delà     (adv)           envers                      pour
        au-dessous  (adv)           ès                          quant à/au/à la/aux
        au-dessus   (adv)           excepté                     revoici
        au-devant   (adv)           face à                      revoilà
        auprès de                   fors                        sauf
        autour de                   grâce à                     sans
        av                          hormis                      selon
        avant                       hors                        sous
        avec                        jusque                      suivant
        chez                        jusques                     sur
        concernant                  lez                         tandis      (adv)
        contre                      lors de                     vers
        courant (+mois)             lès                         versus
        dans                        malgré                      via
        depuis                      moins       (adv)           vis-à-vis
        derrière                    nonobstant  (adv)           voici
        dessous     (adv)           par-delà                    voilà
        dessus      (adv)           par-derrière  (adv)         vs
        devant      (adv)           par-dessous   (adv)         vu


## PRONOMS

    PRONOMS PERSONNELS SUJETS
        je                  moi-même                                mézigue
        tu                  toi-même                                tézigue
        il / elle           lui / lui-même / elle-même              césigue / sézigue
        on
        nous                nous-même / nous-mêmes                  noszigues
        vous                vous-même / vous-mêmes                  voszigues
        ils / elles         eux / eux-mêmes / elles-mêmes           leurszigues

    PRONOMS PERSONNELS OBJETS
        moi                 moi-même                                mézigue
        toi                 toi-même                                tézigue
        lui / elle          lui-même  / elle-même                   césigue / sézigue
        soi                 soi-même
        nous                nous-même / nous-mêmes                  noszigues
        vous                vous-même / vous-mêmes                  voszigues
        eux / elles         eux / eux-mêmes / elles-mêmes           leurszigues

    PRONOMS NÉGATIFS (SUJETS & OBJETS)
        aucun
        aucune
        dégun
        nul
        personne
        rien

    PRONOMS OBJETS PRÉVERBES
        la      COD
        le      COD
        les     COD
        l’      COD
        leur    COI
        lui     COI
        me      COD/COI
        te      COD/COI
        se      COD/COI
        nous    COD/COI
        vous    COD/COI
        y       COI (proadv)
        en      COD (proadv)

    PRONOMS DÉMONSTRATIFS (SUJETS ET OBJETS)
        çuilà           propersuj properobj 3pe mas sg
        ça              prodem mas sg
        ceci            prodem mas sg
        cela            prodem mas sg
        celle qui       prodem fem sg
        celles qui      prodem fem pl
        celle-ci        prodem fem sg
        celle-là        prodem fem sg
        celles-ci       prodem fem pl
        celles-là       prodem fem pl
        celui qui       prodem mas sg
        celui-ci        prodem mas sg
        celui-là        prodem mas sg
        ceux qui        prodem mas pl
        ceux-ci         prodem mas pl
        ceux-là         prodem mas pl

        icelle          detdem prodem fem sg
        icelles         detdem prodem fem pl
        icelui          detdem prodem mas sg
        iceux           detdem prodem mas pl

    PRONOMS DÉMONSTRATIFS (SUJETS)
        ce

    PRONOMS DÉMONSTRATIFS (OBJETS)
        ci              (adv)

    PRONOMS RELATIFS
        auquel          proint prorel mas sg
        auxquelles      proint prorel fem pl
        auxquels        proint prorel mas pl
        desquelles      proint prorel fem pl
        desquels        proint prorel mas pl
        dont            prorel
        duquel          proint prorel mas sg
        laquelle        proint prorel fem sg
        lequel          proint prorel mas sg
        lesquelles      proint prorel fem pl
        lesquels        proint prorel mas pl
        où              advint prorel
        qué             proint prorel
        qui             proint prorel
        que             proint prorel
        quid            proint
        quoi            proint prorel

        autre           proind
        autrui          proind
        quiconque       proind prorel
        certaine        detind proind
        chacun          proind mas sg
        chacune         proind fem sg
        d’aucuns        proind mas pl
        grand-chose     proind
        n’importe quoi  proind
        n’importe qui   proind
        plupart         proind epi pl
        quelques-unes   proind fem pl
        quelques-uns    proind mas pl
        quelqu’un       proind mas sg
        quelqu’une      proind fem sg
        telle           proind

## MOTS GRAMMATICAUX CONFUS

    a
    autour
    cela
    certain·e·s
    contre
    dans
    derrière
    durant
    entre
    excepté
    face
    la
    leur
    lui
    mais
    me
    or
    outre
    personne
    pendant
    plus
    point
    pourvu
    puis
    rien
    sauf
    soit
    son
    sous
    sur
    ton
    tout
    tu
    un
    une
    vers
    y

## VERBES À TRAITER EN PARTICULIER

    # auxiliaire
    être
    avoir
    aller

    # verbes modaux ou quasi-modaux
    adorer
    aimer
    croire
    devoir
    espérer
    faire
    falloir
    imaginer
    laisser
    partir
    penser
    pouvoir
    savoir
    venir
    vouloir

    # verbes d’état
    apparaître
    avoir l’air
    demeurer
    devenir
    paraître
    redevenir
    rester
    sembler

    # verbes d’action usuels
    commencer
    donner
    finir
    prendre
    trouver
    voir

    # dialogue
    - aboyer, accepter, acclamer, accorder, accuser, achever, acquiescer, adhérer, adjurer, admettre, admonester, affirmer, affranchir, ajouter, alléguer, anathématiser, annoncer, annoter, apostropher, appeler, applaudir, apprendre, approuver, approuver, arguer, argumenter, arrêter, articuler, assener, assurer, attester, avancer, avertir, aviser, avouer, ânonner
    - babiller, badiner, bafouer, bafouiller, balbutier, baragouiner, bavarder, beugler, blaguer, blâmer, bougonner, bourdonner, bourrasser, brailler, bramer, bredouiller, bégayer, bénir
    - cafouiller, capituler, certifier, chanter, chantonner, choisir, chuchoter, clamer, combattre, commander, commenter, compatir, compléter, composer, conclure, concéder, confesser, confier, confirmer, congratuler, considérer, conspuer, conter, contester, contredire, converser, couiner, couper, cracher, crachoter, crier, critiquer, croire, crépiter, céder
    - déclamer, demander, deviner, deviser, dialoguer, dire, discourir, discréditer, discuter, disserter, dissimuler, distinguer, divulguer, douter, débiter, décider, déclamer, déclarer, décrire, dédouaner, déduire, défendre, dégoiser, démentir, démontrer, dénoncer, déplorer, détailler, dévoiler
    - emporter, encenser, enchérir, encourager, enflammer, enguirlander, enquérir, entamer, entonner, ergoter, essayer, estimer, exagérer, examiner, exhorter, exiger, expliquer, exploser, exposer, exprimer, exulter, éclater, égosiller, égrener, éjaculer, éluder, émettre, énoncer, énumérer, épeler, établir, éternuer, étonner
    - faire fanfaronner, faire miroiter, faire remarquer, finir, flatter, formuler, fustiger, féliciter
    - garantir, geindre, glisser, glorifier, gloser, glousser, gouailler, grincer, grognasser, grogner, grommeler, gronder, gueuler, gémir
    - haleter, haranguer, hasarder, honnir, huer, hurler, héler, hésiter
    - imaginer, implorer, indiquer, infirmer, informer, injurier, innocenter, insinuer, insister, insister, insulter, intercéder, interdire, interroger, interrompre, intervenir, intimer, inventer, inventorier, invoquer, ironiser
    - jauger, jubiler, juger, jurer, justifier
    - lancer, lire, lister, louer, lâcher
    - marmonner, maugréer, menacer, mentir, mettre en garde, minauder, minimiser, monologuer, murmurer, médire, mépriser
    - narguer, narrer, nasiller, nier, négocier
    - objecter, objurguer, obliger, observer, obtempérer, opiner, ordonner, outrager
    - palabrer, papoter, parlementer, parler, penser, permettre, persifler, pester, philosopher, piaffer, pilorier, plaider, plaisanter, plastronner, pleurer, pleurnicher, polémiquer, pontifier, postillonner, pouffer, poursuivre, prier, proférer, prohiber, promettre, prophétiser, proposer, protester, prouver, préciser, préférer, présenter, prétendre, prôner, psalmodier, pérorer
    - questionner, quémander, quêter
    - rabâcher, raconter, radoter, railler, rajouter, rappeler, rapporter, rassurer, raviser, réciter, reconnaître, rectifier, redire, refuser, regretter, relater, remarquer, renauder, renchérir, renseigner, renâcler, repartir, reprendre, requérir, ressasser, revendiquer, ricaner, riposter, rire, risquer, ronchonner, ronronner, rouscailler, rouspéter, rugir, râler, réaliser, récapituler, réciter, réclamer, récuser, réfuter, répliquer, répliquer, répondre, répondre, réprimander, réprouver, répéter, résister, résumer, rétorquer, réviser, révéler
    - saluer, scruter, se gargariser, se moquer, se plaindre, se réjouir, se souvenir, seriner, sermonner, siffler, signaler, signifier, soliloquer, solliciter, sommer, souffler, souligner, soupçonner, sourire, souscrire, soutenir, stigmatiser, suggérer, supplier, supputer, susurrer, sélectionner, s’adresser, s’esclaffer, s’exclamer, s’excuser, s’impatienter, s’incliner, s’instruire, s’insurger, s’interloquer, s’intéresser, s’offusquer, s’émerveiller, s’étouffer, s’étrangler
    - taquiner, tempérer, tempêter, tenter, terminer, tonitruer, tonner, traduire
    - vanter, vanter, vilipender, vitupérer, vociférer, vomir, vérifier
    - zozoter, zézayer

Modified gc_lang/fr/config.ini from [7c7adf7950] to [30e2946464].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
[args]
lang = fr
lang_name = French
locales = fr_FR fr_BE fr_CA fr_CH fr_LU fr_BF fr_BJ fr_CD fr_CI fr_CM fr_MA fr_ML fr_MU fr_NE fr_RE fr_SN fr_TG 
country_default = FR
name = Grammalecte
implname = grammalecte
# always use 3 numbers for version: x.y.z
version = 0.6.4.2
author = Olivier R.
provider = Dicollecte
link = http://grammalecte.net
description = Correcteur grammatical pour le français.
extras = README_fr.txt
logo = logo.png

................................................................................
# Finite state automaton compression: 1, 2 (experimental) or 3 (experimental)
fsa_method = 1
# stemming method: S for suffixes only, A for prefixes and suffixes
stemming_method = S

# LibreOffice
unopkg = C:/Program Files/LibreOffice/program/unopkg.com
oxt_version = 6.3
oxt_identifier = French.linguistic.resources.from.Dicollecte.by.OlivierR

# Firefox
fx_identifier = French-GC@grammalecte.net
fx_name = Grammalecte [fr]

win_fx_dev_path = C:\Program Files\Firefox Developer Edition\firefox.exe



|




|







 







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
[args]
lang = fr
lang_name = French
locales = fr_FR fr_BE fr_CA fr_CH fr_LU fr_BF fr_BJ fr_CD fr_CI fr_CM fr_MA fr_ML fr_MU fr_NE fr_RE fr_SN fr_TG
country_default = FR
name = Grammalecte
implname = grammalecte
# always use 3 numbers for version: x.y.z
version = 1.0
author = Olivier R.
provider = Dicollecte
link = http://grammalecte.net
description = Correcteur grammatical pour le français.
extras = README_fr.txt
logo = logo.png

................................................................................
# Finite state automaton compression: 1, 2 (experimental) or 3 (experimental)
fsa_method = 1
# stemming method: S for suffixes only, A for prefixes and suffixes
stemming_method = S

# LibreOffice
unopkg = C:/Program Files/LibreOffice/program/unopkg.com
oxt_version = 7.0
oxt_identifier = French.linguistic.resources.from.Dicollecte.by.OlivierR

# Firefox
fx_identifier = French-GC@grammalecte.net
fx_name = Grammalecte [fr]

win_fx_dev_path = C:\Program Files\Firefox Developer Edition\firefox.exe

Modified gc_lang/fr/data/dictConj.txt from [eaf25f2354] to [bff027e827].

20671
20672
20673
20674
20675
20676
20677
20678
20679
20680
20681
20682
20683
20684
20685
.....
31041
31042
31043
31044
31045
31046
31047
31048
31049
31050
31051
31052
31053
31054
31055
......
117064
117065
117066
117067
117068
117069
117070






















































117071
117072
117073
117074
117075
117076
117077
......
140959
140960
140961
140962
140963
140964
140965






















































140966
140967
140968
140969
140970
140971
140972
......
151529
151530
151531
151532
151533
151534
151535






















































151536
151537
151538
151539
151540
151541
151542
......
165695
165696
165697
165698
165699
165700
165701






















































165702
165703
165704
165705
165706
165707
165708
......
191114
191115
191116
191117
191118
191119
191120
191121
191122
191123
191124
191125
191126
191127
191128
191129
191130
191131
191132
191133
191134
191135
191136
191137
191138
191139
191140
191141
191142
191143
191144
191145
191146
191147
191148
191149
191150
191151
191152
191153
191154
191155
191156
191157
191158
191159
191160
191161
191162
191163
191164
191165
......
191313
191314
191315
191316
191317
191318
191319
191320
191321
191322
191323
191324
191325
191326
191327
191328
191329
191330
191331
191332
191333
191334
191335
191336
191337
191338
191339
191340
191341
191342
191343
191344
191345
191346
191347
191348
191349
191350
191351
191352
191353
191354
191355
191356
191357
191358
191359
191360
191361
191362
191363
191364
191365
191366
191367
191368
191369
191370
191371
191372
191373
191374
191375
191376
191377
191378
191379
......
192048
192049
192050
192051
192052
192053
192054
192055
192056
192057
192058
192059
192060
192061
192062
192063
192064
192065
192066
192067
192068
192069
192070
192071
192072
192073
192074
192075
192076
192077
192078
192079
192080
192081
192082
192083
192084
192085
192086
192087
192088
192089
192090
192091
192092
192093
192094
192095
192096
192097
192098
192099
......
192238
192239
192240
192241
192242
192243
192244
192245
192246
192247
192248
192249
192250
192251
192252
......
193412
193413
193414
193415
193416
193417
193418
193419
193420
193421
193422
193423
193424
193425
193426
193427
193428
......
193467
193468
193469
193470
193471
193472
193473




































































































































193474
193475
193476
193477
193478
193479
193480
193481
193482
193483
193484
193485
193486
193487
193488
193489
193490
193491
193492
193493
193494
193495
193496
193497
193498
193499
193500
193501
193502
193503
193504
193505
193506
193507
193508
193509
193510
193511
193512
193513
193514
193515
193516
193517
193518
193519
193520
193521
193522
193523
193524
193525
193526
193527
193528
193529
193530
193531
......
284433
284434
284435
284436
284437
284438
284439






















































284440
284441
284442
284443
284444
284445
284446
......
287494
287495
287496
287497
287498
287499
287500






















































287501
287502
287503
287504
287505
287506
287507
......
300419
300420
300421
300422
300423
300424
300425






















































300426
300427
300428
300429
300430
300431
300432
......
337650
337651
337652
337653
337654
337655
337656






















































337657
337658
337659
337660
337661
337662
337663
......
348921
348922
348923
348924
348925
348926
348927






















































348928
348929
348930
348931
348932
348933
348934
......
353441
353442
353443
353444
353445
353446
353447






















































353448
353449
353450
353451
353452
353453
353454
......
355052
355053
355054
355055
355056
355057
355058






















































355059
355060
355061
355062
355063
355064
355065
......
368786
368787
368788
368789
368790
368791
368792






















































368793
368794
368795
368796
368797
368798
368799
......
369491
369492
369493
369494
369495
369496
369497






















































369498
369499
369500
369501
369502
369503
369504
......
381879
381880
381881
381882
381883
381884
381885
381886
381887
381888
381889
381890
381891
381892
381893
381894
381895
......
382206
382207
382208
382209
382210
382211
382212
382213
382214
382215
382216
382217
382218
382219
382220
382221
382222
......
382749
382750
382751
382752
382753
382754
382755
382756
382757
382758
382759
382760
382761
382762
382763
382764
382765
382766
382767
382768
382769
382770
382771
382772
......
392393
392394
392395
392396
392397
392398
392399
392400
392401
392402
392403
392404
392405
392406
392407
......
406992
406993
406994
406995
406996
406997
406998






















































406999
407000
407001
407002
407003
407004
407005
......
408812
408813
408814
408815
408816
408817
408818
















408819
408820
408821
408822
408823
408824
408825
......
421539
421540
421541
421542
421543
421544
421545






















































421546
421547
421548
421549
421550
421551
421552
......
437860
437861
437862
437863
437864
437865
437866
437867
437868
437869
437870
437871
437872
437873
437874
_	simp 2pl	appontassiez
_	simp 3pl	appontassent
_	impe 2sg	apponte
_	impe 1pl	appontons
_	impe 2pl	appontez
_	ppas epi inv	apponté
$
apporter	1_it____a
_	infi	apporter
_	ppre	apportant
_	ipre 1sg	apporte
_	ipre 3sg	apporte
_	spre 1sg	apporte
_	spre 3sg	apporte
_	ipre 1isg	apportè
................................................................................
_	impe 1pl	avoyons
_	impe 2pl	avoyez
_	ppas mas sg	avoyé
_	ppas mas pl	avoyés
_	ppas fem sg	avoyée
_	ppas fem pl	avoyées
$
axer	1__t_q_zz
_	infi	axer
_	ppre	axant
_	ipre 1sg	axe
_	ipre 3sg	axe
_	spre 1sg	axe
_	spre 3sg	axe
_	ipre 1isg	axè
................................................................................
_	impe 1pl	dégénérons
_	impe 2pl	dégénérez
_	ppas mas sg	dégénéré
_	ppas mas pl	dégénérés
_	ppas fem sg	dégénérée
_	ppas fem pl	dégénérées
$






















































dégermer	1__t___zz
_	infi	dégermer
_	ppre	dégermant
_	ipre 1sg	dégerme
_	ipre 3sg	dégerme
_	spre 1sg	dégerme
_	spre 3sg	dégerme
................................................................................
_	impe 1pl	désentravons
_	impe 2pl	désentravez
_	ppas mas sg	désentravé
_	ppas mas pl	désentravés
_	ppas fem sg	désentravée
_	ppas fem pl	désentravées
$






















































désenvaser	1__t___zz
_	infi	désenvaser
_	ppre	désenvasant
_	ipre 1sg	désenvase
_	ipre 3sg	désenvase
_	spre 1sg	désenvase
_	spre 3sg	désenvase
................................................................................
_	impe 1pl	dézippons
_	impe 2pl	dézippez
_	ppas mas sg	dézippé
_	ppas mas pl	dézippés
_	ppas fem sg	dézippée
_	ppas fem pl	dézippées
$






















































diaboliser	1__t___zz
_	infi	diaboliser
_	ppre	diabolisant
_	ipre 1sg	diabolise
_	ipre 3sg	diabolise
_	spre 1sg	diabolise
_	spre 3sg	diabolise
................................................................................
_	impe 1pl	éditionnons
_	impe 2pl	éditionnez
_	ppas mas sg	éditionné
_	ppas mas pl	éditionnés
_	ppas fem sg	éditionnée
_	ppas fem pl	éditionnées
$






















































édulcorer	1__t___zz
_	infi	édulcorer
_	ppre	édulcorant
_	ipre 1sg	édulcore
_	ipre 3sg	édulcore
_	spre 1sg	édulcore
_	spre 3sg	édulcore
................................................................................
_	impe 1pl	entraimons
_	impe 2pl	entraimez
_	ppas mas sg	entraimé
_	ppas mas pl	entraimés
_	ppas fem sg	entraimée
_	ppas fem pl	entraimées
$
entr'aimer	1____r_e_
_	infi	entr'aimer
_	ppre	entr'aimant
_	ipre 3sg	entr'aime
_	spre 3sg	entr'aime
_	ipre 1pl	entr'aimons
_	ipre 2pl	entr'aimez
_	ipre 3pl	entr'aiment
_	spre 3pl	entr'aiment
_	iimp 3sg	entr'aimait
_	iimp 1pl	entr'aimions
_	spre 1pl	entr'aimions
_	iimp 2pl	entr'aimiez
_	spre 2pl	entr'aimiez
_	iimp 3pl	entr'aimaient
_	ipsi 3sg	entr'aima
_	ipsi 1pl	entr'aimâmes
_	ipsi 2pl	entr'aimâtes
_	ipsi 3pl	entr'aimèrent
_	ifut 3sg	entr'aimera
_	ifut 1pl	entr'aimerons
_	ifut 2pl	entr'aimerez
_	ifut 3pl	entr'aimeront
_	cond 3sg	entr'aimerait
_	cond 1pl	entr'aimerions
_	cond 2pl	entr'aimeriez
_	cond 3pl	entr'aimeraient
_	simp 3sg	entr'aimât
_	simp 1pl	entr'aimassions
_	simp 2pl	entr'aimassiez
_	simp 3pl	entr'aimassent
_	impe 1pl	entr'aimons
_	impe 2pl	entr'aimez
_	ppas mas sg	entr'aimé
_	ppas mas pl	entr'aimés
_	ppas fem sg	entr'aimée
_	ppas fem pl	entr'aimées
$
entrainer	1__t_q__a
_	infi	entrainer
_	ppre	entrainant
_	ipre 1sg	entraine
_	ipre 3sg	entraine
_	spre 1sg	entraine
_	spre 3sg	entraine
................................................................................
_	simp 1pl	entraperçussions
_	simp 2pl	entraperçussiez
_	simp 3pl	entraperçussent
_	impe 2sg	entraperçois
_	impe 1pl	entrapercevons
_	impe 2pl	entrapercevez
$
entr'apercevoir	3__t_q_zz
_	infi	entr'apercevoir
_	ppre	entr'apercevant
_	ppas mas sg	entr'aperçu
_	ppas mas pl	entr'aperçus
_	ppas fem sg	entr'aperçue
_	ppas fem pl	entr'aperçues
_	ipre 1sg	entr'aperçois
_	ipre 2sg	entr'aperçois
_	ipre 3sg	entr'aperçoit
_	ipre 1pl	entr'apercevons
_	ipre 2pl	entr'apercevez
_	ipre 3pl	entr'aperçoivent
_	spre 3pl	entr'aperçoivent
_	iimp 1sg	entr'apercevais
_	iimp 2sg	entr'apercevais
_	iimp 3sg	entr'apercevait
_	iimp 1pl	entr'apercevions
_	spre 1pl	entr'apercevions
_	iimp 2pl	entr'aperceviez
_	spre 2pl	entr'aperceviez
_	iimp 3pl	entr'apercevaient
_	ipsi 1sg	entr'aperçus
_	ipsi 2sg	entr'aperçus
_	ipsi 3sg	entr'aperçut
_	ipsi 1pl	entr'aperçûmes
_	ipsi 2pl	entr'aperçûtes
_	ipsi 3pl	entr'aperçurent
_	ifut 1sg	entr'apercevrai
_	ifut 2sg	entr'apercevras
_	ifut 3sg	entr'apercevra
_	ifut 1pl	entr'apercevrons
_	ifut 2pl	entr'apercevrez
_	ifut 3pl	entr'apercevront
_	cond 1sg	entr'apercevrais
_	cond 2sg	entr'apercevrais
_	cond 3sg	entr'apercevrait
_	cond 1pl	entr'apercevrions
_	cond 2pl	entr'apercevriez
_	cond 3pl	entr'apercevraient
_	spre 1sg	entr'aperçoive
_	spre 3sg	entr'aperçoive
_	spre 2sg	entr'aperçoives
_	simp 1sg	entr'aperçusse
_	simp 2sg	entr'aperçusses
_	simp 3sg	entr'aperçût
_	simp 1pl	entr'aperçussions
_	simp 2pl	entr'aperçussiez
_	simp 3pl	entr'aperçussent
_	impe 2sg	entr'aperçois
_	impe 1pl	entr'apercevons
_	impe 2pl	entr'apercevez
$
entraver	1__t___zz
_	infi	entraver
_	ppre	entravant
_	ipre 1sg	entrave
_	ipre 3sg	entrave
_	spre 1sg	entrave
_	spre 3sg	entrave
................................................................................
_	impe 1pl	entrégorgeons
_	impe 2pl	entrégorgez
_	ppas mas sg	entrégorgé
_	ppas mas pl	entrégorgés
_	ppas fem sg	entrégorgée
_	ppas fem pl	entrégorgées
$
entr'égorger	1____r_e_
_	infi	entr'égorger
_	ppre	entr'égorgeant
_	ipre 3sg	entr'égorge
_	spre 3sg	entr'égorge
_	ipre 1pl	entr'égorgeons
_	ipre 2pl	entr'égorgez
_	ipre 3pl	entr'égorgent
_	spre 3pl	entr'égorgent
_	iimp 3sg	entr'égorgeait
_	iimp 1pl	entr'égorgions
_	spre 1pl	entr'égorgions
_	iimp 2pl	entr'égorgiez
_	spre 2pl	entr'égorgiez
_	iimp 3pl	entr'égorgeaient
_	ipsi 3sg	entr'égorgea
_	ipsi 1pl	entr'égorgeâmes
_	ipsi 2pl	entr'égorgeâtes
_	ipsi 3pl	entr'égorgèrent
_	ifut 3sg	entr'égorgera
_	ifut 1pl	entr'égorgerons
_	ifut 2pl	entr'égorgerez
_	ifut 3pl	entr'égorgeront
_	cond 3sg	entr'égorgerait
_	cond 1pl	entr'égorgerions
_	cond 2pl	entr'égorgeriez
_	cond 3pl	entr'égorgeraient
_	simp 3sg	entr'égorgeât
_	simp 1pl	entr'égorgeassions
_	simp 2pl	entr'égorgeassiez
_	simp 3pl	entr'égorgeassent
_	impe 1pl	entr'égorgeons
_	impe 2pl	entr'égorgez
_	ppas mas sg	entr'égorgé
_	ppas mas pl	entr'égorgés
_	ppas fem sg	entr'égorgée
_	ppas fem pl	entr'égorgées
$
entrehaïr	2____r_e_
_	infi	entrehaïr
_	ppre	entrehaïssant
_	ppas mas sg	entrehaï
_	ppas mas pl	entrehaïs
_	ppas fem sg	entrehaïe
_	ppas fem pl	entrehaïes
................................................................................
_	impe 1pl	entre-heurtons
_	impe 2pl	entre-heurtez
_	ppas mas sg	entre-heurté
_	ppas mas pl	entre-heurtés
_	ppas fem sg	entre-heurtée
_	ppas fem pl	entre-heurtées
$
entrelacer	1__t_q_zz
_	infi	entrelacer
_	ppre	entrelaçant
_	ipre 1sg	entrelace
_	ipre 3sg	entrelace
_	spre 1sg	entrelace
_	spre 3sg	entrelace
_	ipre 1isg	entrelacè
................................................................................
_	impe 1pl	entrevoûtons
_	impe 2pl	entrevoûtez
_	ppas mas sg	entrevoûté
_	ppas mas pl	entrevoûtés
_	ppas fem sg	entrevoûtée
_	ppas fem pl	entrevoûtées
$
entr'hiverner	1__t___zz
_	infi	entr'hiverner
$
entrouvrir	3__t_q_zz
_	infi	entrouvrir
_	ppre	entrouvrant
_	ppas mas sg	entrouvert
_	ppas mas pl	entrouverts
_	ppas fem sg	entrouverte
_	ppas fem pl	entrouvertes
................................................................................
_	simp 1pl	entrouvrissions
_	simp 2pl	entrouvrissiez
_	simp 3pl	entrouvrissent
_	impe 2sg	entrouvre
_	impe 1pl	entrouvrons
_	impe 2pl	entrouvrez
$




































































































































entr'ouvrir	3__t_q_zz
_	infi	entr'ouvrir
_	ppre	entr'ouvrant
_	ppas mas sg	entr'ouvert
_	ppas mas pl	entr'ouverts
_	ppas fem sg	entr'ouverte
_	ppas fem pl	entr'ouvertes
_	ipre 1sg	entr'ouvre
_	ipre 3sg	entr'ouvre
_	spre 1sg	entr'ouvre
_	spre 3sg	entr'ouvre
_	ipre 2sg	entr'ouvres
_	ipre 1pl	entr'ouvrons
_	ipre 2pl	entr'ouvrez
_	ipre 3pl	entr'ouvrent
_	spre 3pl	entr'ouvrent
_	iimp 1sg	entr'ouvrais
_	iimp 2sg	entr'ouvrais
_	iimp 3sg	entr'ouvrait
_	iimp 1pl	entr'ouvrions
_	spre 1pl	entr'ouvrions
_	iimp 2pl	entr'ouvriez
_	spre 2pl	entr'ouvriez
_	iimp 3pl	entr'ouvraient
_	ipsi 1sg	entr'ouvris
_	ipsi 2sg	entr'ouvris
_	ipsi 3sg	entr'ouvrit
_	ipsi 1pl	entr'ouvrîmes
_	ipsi 2pl	entr'ouvrîtes
_	ipsi 3pl	entr'ouvrirent
_	ifut 1sg	entr'ouvrirai
_	ifut 2sg	entr'ouvriras
_	ifut 3sg	entr'ouvrira
_	ifut 1pl	entr'ouvrirons
_	ifut 2pl	entr'ouvrirez
_	ifut 3pl	entr'ouvriront
_	cond 1sg	entr'ouvrirais
_	cond 2sg	entr'ouvrirais
_	cond 3sg	entr'ouvrirait
_	cond 1pl	entr'ouvririons
_	cond 2pl	entr'ouvririez
_	cond 3pl	entr'ouvriraient
_	simp 1sg	entr'ouvrisse
_	simp 2sg	entr'ouvrisses
_	simp 3sg	entr'ouvrît
_	simp 1pl	entr'ouvrissions
_	simp 2pl	entr'ouvrissiez
_	simp 3pl	entr'ouvrissent
_	impe 2sg	entr'ouvre
_	impe 1pl	entr'ouvrons
_	impe 2pl	entr'ouvrez
$
entuber	1__t___zz
_	infi	entuber
_	ppre	entubant
_	ipre 1sg	entube
_	ipre 3sg	entube
_	spre 1sg	entube
................................................................................
_	impe 1pl	nantissons
_	impe 2pl	nantissez
_	ppas mas sg	nanti
_	ppas mas pl	nantis
_	ppas fem sg	nantie
_	ppas fem pl	nanties
$






















































napper	1__t___zz
_	infi	napper
_	ppre	nappant
_	ipre 1sg	nappe
_	ipre 3sg	nappe
_	spre 1sg	nappe
_	spre 3sg	nappe
................................................................................
_	impe 1pl	normalisons
_	impe 2pl	normalisez
_	ppas mas sg	normalisé
_	ppas mas pl	normalisés
_	ppas fem sg	normalisée
_	ppas fem pl	normalisées
$






















































noter	1_it____a
_	infi	noter
_	ppre	notant
_	ipre 1sg	note
_	ipre 3sg	note
_	spre 1sg	note
_	spre 3sg	note
................................................................................
_	impe 1pl	patentons
_	impe 2pl	patentez
_	ppas mas sg	patenté
_	ppas mas pl	patentés
_	ppas fem sg	patentée
_	ppas fem pl	patentées
$






















































patienter	1_i____zz
_	infi	patienter
_	ppre	patientant
_	ipre 1sg	patiente
_	ipre 3sg	patiente
_	spre 1sg	patiente
_	spre 3sg	patiente
................................................................................
_	impe 1pl	réattribuons
_	impe 2pl	réattribuez
_	ppas mas sg	réattribué
_	ppas mas pl	réattribués
_	ppas fem sg	réattribuée
_	ppas fem pl	réattribuées
$






















































rebaisser	1_i____zz
_	infi	rebaisser
_	ppre	rebaissant
_	ipre 1sg	rebaisse
_	ipre 3sg	rebaisse
_	spre 1sg	rebaisse
_	spre 3sg	rebaisse
................................................................................
_	simp 1pl	réentendissions
_	simp 2pl	réentendissiez
_	simp 3pl	réentendissent
_	impe 2sg	réentends
_	impe 1pl	réentendons
_	impe 2pl	réentendez
$






















































rééquilibrer	1__t___zz
_	infi	rééquilibrer
_	ppre	rééquilibrant
_	ipre 1sg	rééquilibre
_	ipre 3sg	rééquilibre
_	spre 1sg	rééquilibre
_	spre 3sg	rééquilibre
................................................................................
_	impe 1pl	rehaussons
_	impe 2pl	rehaussez
_	ppas mas sg	rehaussé
_	ppas mas pl	rehaussés
_	ppas fem sg	rehaussée
_	ppas fem pl	rehaussées
$






















































réhydrater	1__t___zz
_	infi	réhydrater
_	ppre	réhydratant
_	ipre 1sg	réhydrate
_	ipre 3sg	réhydrate
_	spre 1sg	réhydrate
_	spre 3sg	réhydrate
................................................................................
_	impe 1pl	réinvitons
_	impe 2pl	réinvitez
_	ppas mas sg	réinvité
_	ppas mas pl	réinvités
_	ppas fem sg	réinvitée
_	ppas fem pl	réinvitées
$






















































réitérer	1_it___zz
_	infi	réitérer
_	ppre	réitérant
_	ipre 1sg	réitère
_	ipre 3sg	réitère
_	spre 1sg	réitère
_	spre 3sg	réitère
................................................................................
_	impe 1pl	rescindons
_	impe 2pl	rescindez
_	ppas mas sg	rescindé
_	ppas mas pl	rescindés
_	ppas fem sg	rescindée
_	ppas fem pl	rescindées
$






















































réseauter	1_i____zz
_	infi	réseauter
_	ppre	réseautant
_	ipre 1sg	réseaute
_	ipre 3sg	réseaute
_	spre 1sg	réseaute
_	spre 3sg	réseaute
................................................................................
_	impe 1pl	resocialisons
_	impe 2pl	resocialisez
_	ppas mas sg	resocialisé
_	ppas mas pl	resocialisés
_	ppas fem sg	resocialisée
_	ppas fem pl	resocialisées
$






















































résonner	1_i____zz
_	infi	résonner
_	ppre	résonnant
_	ipre 1sg	résonne
_	ipre 3sg	résonne
_	spre 1sg	résonne
_	spre 3sg	résonne
................................................................................
_	impe 1pl	rythmons
_	impe 2pl	rythmez
_	ppas mas sg	rythmé
_	ppas mas pl	rythmés
_	ppas fem sg	rythmée
_	ppas fem pl	rythmées
$
s'abader	1____p_e_
_	infi	s'abader
$
sabler	1_it___zz
_	infi	sabler
_	ppre	sablant
_	ipre 1sg	sable
_	ipre 3sg	sable
_	spre 1sg	sable
_	spre 3sg	sable
................................................................................
_	impe 1pl	sabrons
_	impe 2pl	sabrez
_	ppas mas sg	sabré
_	ppas mas pl	sabrés
_	ppas fem sg	sabrée
_	ppas fem pl	sabrées
$
s'abriller	1____p_e_
_	infi	s'abriller
$
sacagner	1__t___zz
_	infi	sacagner
_	ppre	sacagnant
_	ipre 1sg	sacagne
_	ipre 3sg	sacagne
_	spre 1sg	sacagne
_	spre 3sg	sacagne
................................................................................
_	impe 1pl	safranons
_	impe 2pl	safranez
_	ppas mas sg	safrané
_	ppas mas pl	safranés
_	ppas fem sg	safranée
_	ppas fem pl	safranées
$
s'agir	2____p_e_
_	infi	s'agir
_	ppre	s'agissant
_	ipre 3sg	s'agit
_	iimp 3sg	s'agissait
_	ifut 3sg	s'agira
_	cond 3sg	s'agirait
_	spre 3sg	s'agisse
_	simp 3sg	s'agît
$
saietter	1__t___zz
_	infi	saietter
_	ppre	saiettant
_	ipre 1sg	saiette
_	ipre 3sg	saiette
_	spre 1sg	saiette
_	spre 3sg	saiette
................................................................................
_	impe 1pl	solidarisons
_	impe 2pl	solidarisez
_	ppas mas sg	solidarisé
_	ppas mas pl	solidarisés
_	ppas fem sg	solidarisée
_	ppas fem pl	solidarisées
$
solidifier	1__t_q_zz
_	infi	solidifier
_	ppre	solidifiant
_	ipre 1sg	solidifie
_	ipre 3sg	solidifie
_	spre 1sg	solidifie
_	spre 3sg	solidifie
_	ipre 1isg	solidifiè
................................................................................
_	simp 1pl	sursissions
_	simp 2pl	sursissiez
_	simp 3pl	sursissent
_	impe 2sg	sursois
_	impe 1pl	sursoyons
_	impe 2pl	sursoyez
$






















































sursouffler	1__t___zz
_	infi	sursouffler
_	ppre	sursoufflant
_	ipre 1sg	sursouffle
_	ipre 3sg	sursouffle
_	spre 1sg	sursouffle
_	spre 3sg	sursouffle
................................................................................
_	impe 2sg	systématise
_	impe 1pl	systématisons
_	impe 2pl	systématisez
_	ppas mas sg	systématisé
_	ppas mas pl	systématisés
_	ppas fem sg	systématisée
_	ppas fem pl	systématisées
















$
tabasser	1__t_q_zz
_	infi	tabasser
_	ppre	tabassant
_	ipre 1sg	tabasse
_	ipre 3sg	tabasse
_	spre 1sg	tabasse
................................................................................
_	impe 1pl	transitons
_	impe 2pl	transitez
_	ppas mas sg	transité
_	ppas mas pl	transités
_	ppas fem sg	transitée
_	ppas fem pl	transitées
$






















































translater	1__t___zz
_	infi	translater
_	ppre	translatant
_	ipre 1sg	translate
_	ipre 3sg	translate
_	spre 1sg	translate
_	spre 3sg	translate
................................................................................
_	simp 2pl	zonzonnassiez
_	simp 3pl	zonzonnassent
_	impe 2sg	zonzonne
_	impe 1pl	zonzonnons
_	impe 2pl	zonzonnez
_	ppas epi inv	zonzonné
$
zoomer	1__tn__zz
_	infi	zoomer
_	ppre	zoomant
_	ipre 1sg	zoome
_	ipre 3sg	zoome
_	spre 1sg	zoome
_	spre 3sg	zoome
_	ipre 1isg	zoomè







|







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







|







 







<
<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<
<
<







 







<
<
<







 







<
<
<
<
<
<
<
<
<
<







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







20671
20672
20673
20674
20675
20676
20677
20678
20679
20680
20681
20682
20683
20684
20685
.....
31041
31042
31043
31044
31045
31046
31047
31048
31049
31050
31051
31052
31053
31054
31055
......
117064
117065
117066
117067
117068
117069
117070
117071
117072
117073
117074
117075
117076
117077
117078
117079
117080
117081
117082
117083
117084
117085
117086
117087
117088
117089
117090
117091
117092
117093
117094
117095
117096
117097
117098
117099
117100
117101
117102
117103
117104
117105
117106
117107
117108
117109
117110
117111
117112
117113
117114
117115
117116
117117
117118
117119
117120
117121
117122
117123
117124
117125
117126
117127
117128
117129
117130
117131
......
141013
141014
141015
141016
141017
141018
141019
141020
141021
141022
141023
141024
141025
141026
141027
141028
141029
141030
141031
141032
141033
141034
141035
141036
141037
141038
141039
141040
141041
141042
141043
141044
141045
141046
141047
141048
141049
141050
141051
141052
141053
141054
141055
141056
141057
141058
141059
141060
141061
141062
141063
141064
141065
141066
141067
141068
141069
141070
141071
141072
141073
141074
141075
141076
141077
141078
141079
141080
......
151637
151638
151639
151640
151641
151642
151643
151644
151645
151646
151647
151648
151649
151650
151651
151652
151653
151654
151655
151656
151657
151658
151659
151660
151661
151662
151663
151664
151665
151666
151667
151668
151669
151670
151671
151672
151673
151674
151675
151676
151677
151678
151679
151680
151681
151682
151683
151684
151685
151686
151687
151688
151689
151690
151691
151692
151693
151694
151695
151696
151697
151698
151699
151700
151701
151702
151703
151704
......
165857
165858
165859
165860
165861
165862
165863
165864
165865
165866
165867
165868
165869
165870
165871
165872
165873
165874
165875
165876
165877
165878
165879
165880
165881
165882
165883
165884
165885
165886
165887
165888
165889
165890
165891
165892
165893
165894
165895
165896
165897
165898
165899
165900
165901
165902
165903
165904
165905
165906
165907
165908
165909
165910
165911
165912
165913
165914
165915
165916
165917
165918
165919
165920
165921
165922
165923
165924
......
191330
191331
191332
191333
191334
191335
191336






































191337
191338
191339
191340
191341
191342
191343
......
191491
191492
191493
191494
191495
191496
191497





















































191498
191499
191500
191501
191502
191503
191504
......
192173
192174
192175
192176
192177
192178
192179






































192180
192181
192182
192183
192184
192185
192186
......
192325
192326
192327
192328
192329
192330
192331
192332
192333
192334
192335
192336
192337
192338
192339
......
193499
193500
193501
193502
193503
193504
193505



193506
193507
193508
193509
193510
193511
193512
......
193551
193552
193553
193554
193555
193556
193557
193558
193559
193560
193561
193562
193563
193564
193565
193566
193567
193568
193569
193570
193571
193572
193573
193574
193575
193576
193577
193578
193579
193580
193581
193582
193583
193584
193585
193586
193587
193588
193589
193590
193591
193592
193593
193594
193595
193596
193597
193598
193599
193600
193601
193602
193603
193604
193605
193606
193607
193608
193609
193610
193611
193612
193613
193614
193615
193616
193617
193618
193619
193620
193621
193622
193623
193624
193625
193626
193627
193628
193629
193630
193631
193632
193633
193634
193635
193636
193637
193638
193639
193640
193641
193642
193643
193644
193645
193646
193647
193648
193649
193650
193651
193652
193653
193654
193655
193656
193657
193658
193659
193660
193661
193662
193663
193664
193665
193666
193667
193668
193669
193670
193671
193672
193673
193674
193675
193676
193677
193678
193679
193680
193681
193682
193683
193684
193685
193686
193687
193688
193689
193690
193691
193692
193693
193694
193695
193696
193697
193698
193699
193700
193701
193702
193703
193704
193705
193706
193707
193708
193709
193710
193711
193712
193713
193714
193715
193716
193717
193718
193719
193720
193721
193722
193723
193724
193725
193726
193727
193728
193729
193730
193731
193732
193733
193734
193735
193736
193737
193738
193739
193740
193741
193742
193743
193744
193745
193746
193747
......
284649
284650
284651
284652
284653
284654
284655
284656
284657
284658
284659
284660
284661
284662
284663
284664
284665
284666
284667
284668
284669
284670
284671
284672
284673
284674
284675
284676
284677
284678
284679
284680
284681
284682
284683
284684
284685
284686
284687
284688
284689
284690
284691
284692
284693
284694
284695
284696
284697
284698
284699
284700
284701
284702
284703
284704
284705
284706
284707
284708
284709
284710
284711
284712
284713
284714
284715
284716
......
287764
287765
287766
287767
287768
287769
287770
287771
287772
287773
287774
287775
287776
287777
287778
287779
287780
287781
287782
287783
287784
287785
287786
287787
287788
287789
287790
287791
287792
287793
287794
287795
287796
287797
287798
287799
287800
287801
287802
287803
287804
287805
287806
287807
287808
287809
287810
287811
287812
287813
287814
287815
287816
287817
287818
287819
287820
287821
287822
287823
287824
287825
287826
287827
287828
287829
287830
287831
......
300743
300744
300745
300746
300747
300748
300749
300750
300751
300752
300753
300754
300755
300756
300757
300758
300759
300760
300761
300762
300763
300764
300765
300766
300767
300768
300769
300770
300771
300772
300773
300774
300775
300776
300777
300778
300779
300780
300781
300782
300783
300784
300785
300786
300787
300788
300789
300790
300791
300792
300793
300794
300795
300796
300797
300798
300799
300800
300801
300802
300803
300804
300805
300806
300807
300808
300809
300810
......
338028
338029
338030
338031
338032
338033
338034
338035
338036
338037
338038
338039
338040
338041
338042
338043
338044
338045
338046
338047
338048
338049
338050
338051
338052
338053
338054
338055
338056
338057
338058
338059
338060
338061
338062
338063
338064
338065
338066
338067
338068
338069
338070
338071
338072
338073
338074
338075
338076
338077
338078
338079
338080
338081
338082
338083
338084
338085
338086
338087
338088
338089
338090
338091
338092
338093
338094
338095
......
349353
349354
349355
349356
349357
349358
349359
349360
349361
349362
349363
349364
349365
349366
349367
349368
349369
349370
349371
349372
349373
349374
349375
349376
349377
349378
349379
349380
349381
349382
349383
349384
349385
349386
349387
349388
349389
349390
349391
349392
349393
349394
349395
349396
349397
349398
349399
349400
349401
349402
349403
349404
349405
349406
349407
349408
349409
349410
349411
349412
349413
349414
349415
349416
349417
349418
349419
349420
......
353927
353928
353929
353930
353931
353932
353933
353934
353935
353936
353937
353938
353939
353940
353941
353942
353943
353944
353945
353946
353947
353948
353949
353950
353951
353952
353953
353954
353955
353956
353957
353958
353959
353960
353961
353962
353963
353964
353965
353966
353967
353968
353969
353970
353971
353972
353973
353974
353975
353976
353977
353978
353979
353980
353981
353982
353983
353984
353985
353986
353987
353988
353989
353990
353991
353992
353993
353994
......
355592
355593
355594
355595
355596
355597
355598
355599
355600
355601
355602
355603
355604
355605
355606
355607
355608
355609
355610
355611
355612
355613
355614
355615
355616
355617
355618
355619
355620
355621
355622
355623
355624
355625
355626
355627
355628
355629
355630
355631
355632
355633
355634
355635
355636
355637
355638
355639
355640
355641
355642
355643
355644
355645
355646
355647
355648
355649
355650
355651
355652
355653
355654
355655
355656
355657
355658
355659
......
369380
369381
369382
369383
369384
369385
369386
369387
369388
369389
369390
369391
369392
369393
369394
369395
369396
369397
369398
369399
369400
369401
369402
369403
369404
369405
369406
369407
369408
369409
369410
369411
369412
369413
369414
369415
369416
369417
369418
369419
369420
369421
369422
369423
369424
369425
369426
369427
369428
369429
369430
369431
369432
369433
369434
369435
369436
369437
369438
369439
369440
369441
369442
369443
369444
369445
369446
369447
......
370139
370140
370141
370142
370143
370144
370145
370146
370147
370148
370149
370150
370151
370152
370153
370154
370155
370156
370157
370158
370159
370160
370161
370162
370163
370164
370165
370166
370167
370168
370169
370170
370171
370172
370173
370174
370175
370176
370177
370178
370179
370180
370181
370182
370183
370184
370185
370186
370187
370188
370189
370190
370191
370192
370193
370194
370195
370196
370197
370198
370199
370200
370201
370202
370203
370204
370205
370206
......
382581
382582
382583
382584
382585
382586
382587



382588
382589
382590
382591
382592
382593
382594
......
382905
382906
382907
382908
382909
382910
382911



382912
382913
382914
382915
382916
382917
382918
......
383445
383446
383447
383448
383449
383450
383451










383452
383453
383454
383455
383456
383457
383458
......
393079
393080
393081
393082
393083
393084
393085
393086
393087
393088
393089
393090
393091
393092
393093
......
407678
407679
407680
407681
407682
407683
407684
407685
407686
407687
407688
407689
407690
407691
407692
407693
407694
407695
407696
407697
407698
407699
407700
407701
407702
407703
407704
407705
407706
407707
407708
407709
407710
407711
407712
407713
407714
407715
407716
407717
407718
407719
407720
407721
407722
407723
407724
407725
407726
407727
407728
407729
407730
407731
407732
407733
407734
407735
407736
407737
407738
407739
407740
407741
407742
407743
407744
407745
......
409552
409553
409554
409555
409556
409557
409558
409559
409560
409561
409562
409563
409564
409565
409566
409567
409568
409569
409570
409571
409572
409573
409574
409575
409576
409577
409578
409579
409580
409581
......
422295
422296
422297
422298
422299
422300
422301
422302
422303
422304
422305
422306
422307
422308
422309
422310
422311
422312
422313
422314
422315
422316
422317
422318
422319
422320
422321
422322
422323
422324
422325
422326
422327
422328
422329
422330
422331
422332
422333
422334
422335
422336
422337
422338
422339
422340
422341
422342
422343
422344
422345
422346
422347
422348
422349
422350
422351
422352
422353
422354
422355
422356
422357
422358
422359
422360
422361
422362
......
438670
438671
438672
438673
438674
438675
438676
438677
438678
438679
438680
438681
438682
438683
438684
_	simp 2pl	appontassiez
_	simp 3pl	appontassent
_	impe 2sg	apponte
_	impe 1pl	appontons
_	impe 2pl	appontez
_	ppas epi inv	apponté
$
apporter	1_itn___a
_	infi	apporter
_	ppre	apportant
_	ipre 1sg	apporte
_	ipre 3sg	apporte
_	spre 1sg	apporte
_	spre 3sg	apporte
_	ipre 1isg	apportè
................................................................................
_	impe 1pl	avoyons
_	impe 2pl	avoyez
_	ppas mas sg	avoyé
_	ppas mas pl	avoyés
_	ppas fem sg	avoyée
_	ppas fem pl	avoyées
$
axer	1__t_q__a
_	infi	axer
_	ppre	axant
_	ipre 1sg	axe
_	ipre 3sg	axe
_	spre 1sg	axe
_	spre 3sg	axe
_	ipre 1isg	axè
................................................................................
_	impe 1pl	dégénérons
_	impe 2pl	dégénérez
_	ppas mas sg	dégénéré
_	ppas mas pl	dégénérés
_	ppas fem sg	dégénérée
_	ppas fem pl	dégénérées
$
dégenrer	1__t_q__a
_	infi	dégenrer
_	ppre	dégenrant
_	ipre 1sg	dégenre
_	ipre 3sg	dégenre
_	spre 1sg	dégenre
_	spre 3sg	dégenre
_	ipre 1isg	dégenrè
_	ipre 2sg	dégenres
_	spre 2sg	dégenres
_	ipre 1pl	dégenrons
_	ipre 2pl	dégenrez
_	ipre 3pl	dégenrent
_	spre 3pl	dégenrent
_	iimp 1sg	dégenrais
_	iimp 2sg	dégenrais
_	iimp 3sg	dégenrait
_	iimp 1pl	dégenrions
_	spre 1pl	dégenrions
_	iimp 2pl	dégenriez
_	spre 2pl	dégenriez
_	iimp 3pl	dégenraient
_	ipsi 1sg	dégenrai
_	ipsi 2sg	dégenras
_	ipsi 3sg	dégenra
_	ipsi 1pl	dégenrâmes
_	ipsi 2pl	dégenrâtes
_	ipsi 3pl	dégenrèrent
_	ifut 1sg	dégenrerai
_	ifut 2sg	dégenreras
_	ifut 3sg	dégenrera
_	ifut 1pl	dégenrerons
_	ifut 2pl	dégenrerez
_	ifut 3pl	dégenreront
_	cond 1sg	dégenrerais
_	cond 2sg	dégenrerais
_	cond 3sg	dégenrerait
_	cond 1pl	dégenrerions
_	cond 2pl	dégenreriez
_	cond 3pl	dégenreraient
_	simp 1sg	dégenrasse
_	simp 2sg	dégenrasses
_	simp 3sg	dégenrât
_	simp 1pl	dégenrassions
_	simp 2pl	dégenrassiez
_	simp 3pl	dégenrassent
_	impe 2sg	dégenre
_	impe 1pl	dégenrons
_	impe 2pl	dégenrez
_	ppas mas sg	dégenré
_	ppas mas pl	dégenrés
_	ppas fem sg	dégenrée
_	ppas fem pl	dégenrées
$
dégermer	1__t___zz
_	infi	dégermer
_	ppre	dégermant
_	ipre 1sg	dégerme
_	ipre 3sg	dégerme
_	spre 1sg	dégerme
_	spre 3sg	dégerme
................................................................................
_	impe 1pl	désentravons
_	impe 2pl	désentravez
_	ppas mas sg	désentravé
_	ppas mas pl	désentravés
_	ppas fem sg	désentravée
_	ppas fem pl	désentravées
$
désentrelacer	1__t_q__a
_	infi	désentrelacer
_	ppre	désentrelaçant
_	ipre 1sg	désentrelace
_	ipre 3sg	désentrelace
_	spre 1sg	désentrelace
_	spre 3sg	désentrelace
_	ipre 1isg	désentrelacè
_	ipre 2sg	désentrelaces
_	spre 2sg	désentrelaces
_	ipre 1pl	désentrelaçons
_	ipre 2pl	désentrelacez
_	ipre 3pl	désentrelacent
_	spre 3pl	désentrelacent
_	iimp 1sg	désentrelaçais
_	iimp 2sg	désentrelaçais
_	iimp 3sg	désentrelaçait
_	iimp 1pl	désentrelacions
_	spre 1pl	désentrelacions
_	iimp 2pl	désentrelaciez
_	spre 2pl	désentrelaciez
_	iimp 3pl	désentrelaçaient
_	ipsi 1sg	désentrelaçai
_	ipsi 2sg	désentrelaças
_	ipsi 3sg	désentrelaça
_	ipsi 1pl	désentrelaçâmes
_	ipsi 2pl	désentrelaçâtes
_	ipsi 3pl	désentrelacèrent
_	ifut 1sg	désentrelacerai
_	ifut 2sg	désentrelaceras
_	ifut 3sg	désentrelacera
_	ifut 1pl	désentrelacerons
_	ifut 2pl	désentrelacerez
_	ifut 3pl	désentrelaceront
_	cond 1sg	désentrelacerais
_	cond 2sg	désentrelacerais
_	cond 3sg	désentrelacerait
_	cond 1pl	désentrelacerions
_	cond 2pl	désentrelaceriez
_	cond 3pl	désentrelaceraient
_	simp 1sg	désentrelaçasse
_	simp 2sg	désentrelaçasses
_	simp 3sg	désentrelaçât
_	simp 1pl	désentrelaçassions
_	simp 2pl	désentrelaçassiez
_	simp 3pl	désentrelaçassent
_	impe 2sg	désentrelace
_	impe 1pl	désentrelaçons
_	impe 2pl	désentrelacez
_	ppas mas sg	désentrelacé
_	ppas mas pl	désentrelacés
_	ppas fem sg	désentrelacée
_	ppas fem pl	désentrelacées
$
désenvaser	1__t___zz
_	infi	désenvaser
_	ppre	désenvasant
_	ipre 1sg	désenvase
_	ipre 3sg	désenvase
_	spre 1sg	désenvase
_	spre 3sg	désenvase
................................................................................
_	impe 1pl	dézippons
_	impe 2pl	dézippez
_	ppas mas sg	dézippé
_	ppas mas pl	dézippés
_	ppas fem sg	dézippée
_	ppas fem pl	dézippées
$
dézoomer	1_it____a
_	infi	dézoomer
_	ppre	dézoomant
_	ipre 1sg	dézoome
_	ipre 3sg	dézoome
_	spre 1sg	dézoome
_	spre 3sg	dézoome
_	ipre 1isg	dézoomè
_	ipre 2sg	dézoomes
_	spre 2sg	dézoomes
_	ipre 1pl	dézoomons
_	ipre 2pl	dézoomez
_	ipre 3pl	dézooment
_	spre 3pl	dézooment
_	iimp 1sg	dézoomais
_	iimp 2sg	dézoomais
_	iimp 3sg	dézoomait
_	iimp 1pl	dézoomions
_	spre 1pl	dézoomions
_	iimp 2pl	dézoomiez
_	spre 2pl	dézoomiez
_	iimp 3pl	dézoomaient
_	ipsi 1sg	dézoomai
_	ipsi 2sg	dézoomas
_	ipsi 3sg	dézooma
_	ipsi 1pl	dézoomâmes
_	ipsi 2pl	dézoomâtes
_	ipsi 3pl	dézoomèrent
_	ifut 1sg	dézoomerai
_	ifut 2sg	dézoomeras
_	ifut 3sg	dézoomera
_	ifut 1pl	dézoomerons
_	ifut 2pl	dézoomerez
_	ifut 3pl	dézoomeront
_	cond 1sg	dézoomerais
_	cond 2sg	dézoomerais
_	cond 3sg	dézoomerait
_	cond 1pl	dézoomerions
_	cond 2pl	dézoomeriez
_	cond 3pl	dézoomeraient
_	simp 1sg	dézoomasse
_	simp 2sg	dézoomasses
_	simp 3sg	dézoomât
_	simp 1pl	dézoomassions
_	simp 2pl	dézoomassiez
_	simp 3pl	dézoomassent
_	impe 2sg	dézoome
_	impe 1pl	dézoomons
_	impe 2pl	dézoomez
_	ppas mas sg	dézoomé
_	ppas mas pl	dézoomés
_	ppas fem sg	dézoomée
_	ppas fem pl	dézoomées
$
diaboliser	1__t___zz
_	infi	diaboliser
_	ppre	diabolisant
_	ipre 1sg	diabolise
_	ipre 3sg	diabolise
_	spre 1sg	diabolise
_	spre 3sg	diabolise
................................................................................
_	impe 1pl	éditionnons
_	impe 2pl	éditionnez
_	ppas mas sg	éditionné
_	ppas mas pl	éditionnés
_	ppas fem sg	éditionnée
_	ppas fem pl	éditionnées
$
éditorialiser	1_it____a
_	infi	éditorialiser
_	ppre	éditorialisant
_	ipre 1sg	éditorialise
_	ipre 3sg	éditorialise
_	spre 1sg	éditorialise
_	spre 3sg	éditorialise
_	ipre 1isg	éditorialisè
_	ipre 2sg	éditorialises
_	spre 2sg	éditorialises
_	ipre 1pl	éditorialisons
_	ipre 2pl	éditorialisez
_	ipre 3pl	éditorialisent
_	spre 3pl	éditorialisent
_	iimp 1sg	éditorialisais
_	iimp 2sg	éditorialisais
_	iimp 3sg	éditorialisait
_	iimp 1pl	éditorialisions
_	spre 1pl	éditorialisions
_	iimp 2pl	éditorialisiez
_	spre 2pl	éditorialisiez
_	iimp 3pl	éditorialisaient
_	ipsi 1sg	éditorialisai
_	ipsi 2sg	éditorialisas
_	ipsi 3sg	éditorialisa
_	ipsi 1pl	éditorialisâmes
_	ipsi 2pl	éditorialisâtes
_	ipsi 3pl	éditorialisèrent
_	ifut 1sg	éditorialiserai
_	ifut 2sg	éditorialiseras
_	ifut 3sg	éditorialisera
_	ifut 1pl	éditorialiserons
_	ifut 2pl	éditorialiserez
_	ifut 3pl	éditorialiseront
_	cond 1sg	éditorialiserais
_	cond 2sg	éditorialiserais
_	cond 3sg	éditorialiserait
_	cond 1pl	éditorialiserions
_	cond 2pl	éditorialiseriez
_	cond 3pl	éditorialiseraient
_	simp 1sg	éditorialisasse
_	simp 2sg	éditorialisasses
_	simp 3sg	éditorialisât
_	simp 1pl	éditorialisassions
_	simp 2pl	éditorialisassiez
_	simp 3pl	éditorialisassent
_	impe 2sg	éditorialise
_	impe 1pl	éditorialisons
_	impe 2pl	éditorialisez
_	ppas mas sg	éditorialisé
_	ppas mas pl	éditorialisés
_	ppas fem sg	éditorialisée
_	ppas fem pl	éditorialisées
$
édulcorer	1__t___zz
_	infi	édulcorer
_	ppre	édulcorant
_	ipre 1sg	édulcore
_	ipre 3sg	édulcore
_	spre 1sg	édulcore
_	spre 3sg	édulcore
................................................................................
_	impe 1pl	entraimons
_	impe 2pl	entraimez
_	ppas mas sg	entraimé
_	ppas mas pl	entraimés
_	ppas fem sg	entraimée
_	ppas fem pl	entraimées
$






































entrainer	1__t_q__a
_	infi	entrainer
_	ppre	entrainant
_	ipre 1sg	entraine
_	ipre 3sg	entraine
_	spre 1sg	entraine
_	spre 3sg	entraine
................................................................................
_	simp 1pl	entraperçussions
_	simp 2pl	entraperçussiez
_	simp 3pl	entraperçussent
_	impe 2sg	entraperçois
_	impe 1pl	entrapercevons
_	impe 2pl	entrapercevez
$





















































entraver	1__t___zz
_	infi	entraver
_	ppre	entravant
_	ipre 1sg	entrave
_	ipre 3sg	entrave
_	spre 1sg	entrave
_	spre 3sg	entrave
................................................................................
_	impe 1pl	entrégorgeons
_	impe 2pl	entrégorgez
_	ppas mas sg	entrégorgé
_	ppas mas pl	entrégorgés
_	ppas fem sg	entrégorgée
_	ppas fem pl	entrégorgées
$






































entrehaïr	2____r_e_
_	infi	entrehaïr
_	ppre	entrehaïssant
_	ppas mas sg	entrehaï
_	ppas mas pl	entrehaïs
_	ppas fem sg	entrehaïe
_	ppas fem pl	entrehaïes
................................................................................
_	impe 1pl	entre-heurtons
_	impe 2pl	entre-heurtez
_	ppas mas sg	entre-heurté
_	ppas mas pl	entre-heurtés
_	ppas fem sg	entre-heurtée
_	ppas fem pl	entre-heurtées
$
entrelacer	1__t_q__a
_	infi	entrelacer
_	ppre	entrelaçant
_	ipre 1sg	entrelace
_	ipre 3sg	entrelace
_	spre 1sg	entrelace
_	spre 3sg	entrelace
_	ipre 1isg	entrelacè
................................................................................
_	impe 1pl	entrevoûtons
_	impe 2pl	entrevoûtez
_	ppas mas sg	entrevoûté
_	ppas mas pl	entrevoûtés
_	ppas fem sg	entrevoûtée
_	ppas fem pl	entrevoûtées
$



entrouvrir	3__t_q_zz
_	infi	entrouvrir
_	ppre	entrouvrant
_	ppas mas sg	entrouvert
_	ppas mas pl	entrouverts
_	ppas fem sg	entrouverte
_	ppas fem pl	entrouvertes
................................................................................
_	simp 1pl	entrouvrissions
_	simp 2pl	entrouvrissiez
_	simp 3pl	entrouvrissent
_	impe 2sg	entrouvre
_	impe 1pl	entrouvrons
_	impe 2pl	entrouvrez
$
entr’aimer	1____r_e_
_	infi	entr’aimer
_	ppre	entr’aimant
_	ipre 3sg	entr’aime
_	spre 3sg	entr’aime
_	ipre 1pl	entr’aimons
_	ipre 2pl	entr’aimez
_	ipre 3pl	entr’aiment
_	spre 3pl	entr’aiment
_	iimp 3sg	entr’aimait
_	iimp 1pl	entr’aimions
_	spre 1pl	entr’aimions
_	iimp 2pl	entr’aimiez
_	spre 2pl	entr’aimiez
_	iimp 3pl	entr’aimaient
_	ipsi 3sg	entr’aima
_	ipsi 1pl	entr’aimâmes
_	ipsi 2pl	entr’aimâtes
_	ipsi 3pl	entr’aimèrent
_	ifut 3sg	entr’aimera
_	ifut 1pl	entr’aimerons
_	ifut 2pl	entr’aimerez
_	ifut 3pl	entr’aimeront
_	cond 3sg	entr’aimerait
_	cond 1pl	entr’aimerions
_	cond 2pl	entr’aimeriez
_	cond 3pl	entr’aimeraient
_	simp 3sg	entr’aimât
_	simp 1pl	entr’aimassions
_	simp 2pl	entr’aimassiez
_	simp 3pl	entr’aimassent
_	impe 1pl	entr’aimons
_	impe 2pl	entr’aimez
_	ppas mas sg	entr’aimé
_	ppas mas pl	entr’aimés
_	ppas fem sg	entr’aimée
_	ppas fem pl	entr’aimées
$
entr’apercevoir	3__t_q_zz
_	infi	entr’apercevoir
_	ppre	entr’apercevant
_	ppas mas sg	entr’aperçu
_	ppas mas pl	entr’aperçus
_	ppas fem sg	entr’aperçue
_	ppas fem pl	entr’aperçues
_	ipre 1sg	entr’aperçois
_	ipre 2sg	entr’aperçois
_	ipre 3sg	entr’aperçoit
_	ipre 1pl	entr’apercevons
_	ipre 2pl	entr’apercevez
_	ipre 3pl	entr’aperçoivent
_	spre 3pl	entr’aperçoivent
_	iimp 1sg	entr’apercevais
_	iimp 2sg	entr’apercevais
_	iimp 3sg	entr’apercevait
_	iimp 1pl	entr’apercevions
_	spre 1pl	entr’apercevions
_	iimp 2pl	entr’aperceviez
_	spre 2pl	entr’aperceviez
_	iimp 3pl	entr’apercevaient
_	ipsi 1sg	entr’aperçus
_	ipsi 2sg	entr’aperçus
_	ipsi 3sg	entr’aperçut
_	ipsi 1pl	entr’aperçûmes
_	ipsi 2pl	entr’aperçûtes
_	ipsi 3pl	entr’aperçurent
_	ifut 1sg	entr’apercevrai
_	ifut 2sg	entr’apercevras
_	ifut 3sg	entr’apercevra
_	ifut 1pl	entr’apercevrons
_	ifut 2pl	entr’apercevrez
_	ifut 3pl	entr’apercevront
_	cond 1sg	entr’apercevrais
_	cond 2sg	entr’apercevrais
_	cond 3sg	entr’apercevrait
_	cond 1pl	entr’apercevrions
_	cond 2pl	entr’apercevriez
_	cond 3pl	entr’apercevraient
_	spre 1sg	entr’aperçoive
_	spre 3sg	entr’aperçoive
_	spre 2sg	entr’aperçoives
_	simp 1sg	entr’aperçusse
_	simp 2sg	entr’aperçusses
_	simp 3sg	entr’aperçût
_	simp 1pl	entr’aperçussions
_	simp 2pl	entr’aperçussiez
_	simp 3pl	entr’aperçussent
_	impe 2sg	entr’aperçois
_	impe 1pl	entr’apercevons
_	impe 2pl	entr’apercevez
$
entr’égorger	1____r_e_
_	infi	entr’égorger
_	ppre	entr’égorgeant
_	ipre 3sg	entr’égorge
_	spre 3sg	entr’égorge
_	ipre 1pl	entr’égorgeons
_	ipre 2pl	entr’égorgez
_	ipre 3pl	entr’égorgent
_	spre 3pl	entr’égorgent
_	iimp 3sg	entr’égorgeait
_	iimp 1pl	entr’égorgions
_	spre 1pl	entr’égorgions
_	iimp 2pl	entr’égorgiez
_	spre 2pl	entr’égorgiez
_	iimp 3pl	entr’égorgeaient
_	ipsi 3sg	entr’égorgea
_	ipsi 1pl	entr’égorgeâmes
_	ipsi 2pl	entr’égorgeâtes
_	ipsi 3pl	entr’égorgèrent
_	ifut 3sg	entr’égorgera
_	ifut 1pl	entr’égorgerons
_	ifut 2pl	entr’égorgerez
_	ifut 3pl	entr’égorgeront
_	cond 3sg	entr’égorgerait
_	cond 1pl	entr’égorgerions
_	cond 2pl	entr’égorgeriez
_	cond 3pl	entr’égorgeraient
_	simp 3sg	entr’égorgeât
_	simp 1pl	entr’égorgeassions
_	simp 2pl	entr’égorgeassiez
_	simp 3pl	entr’égorgeassent
_	impe 1pl	entr’égorgeons
_	impe 2pl	entr’égorgez
_	ppas mas sg	entr’égorgé
_	ppas mas pl	entr’égorgés
_	ppas fem sg	entr’égorgée
_	ppas fem pl	entr’égorgées
$
entr’hiverner	1__t___zz
_	infi	entr’hiverner
$
entrouvrir	3__t_q_zz
_	infi	entrouvrir
_	ppre	entrouvrant
_	ppas mas sg	entrouvert
_	ppas mas pl	entrouverts
_	ppas fem sg	entrouverte
_	ppas fem pl	entrouvertes
_	ipre 1sg	entrouvre
_	ipre 3sg	entrouvre
_	spre 1sg	entrouvre
_	spre 3sg	entrouvre
_	ipre 2sg	entrouvres
_	ipre 1pl	entrouvrons
_	ipre 2pl	entrouvrez
_	ipre 3pl	entrouvrent
_	spre 3pl	entrouvrent
_	iimp 1sg	entrouvrais
_	iimp 2sg	entrouvrais
_	iimp 3sg	entrouvrait
_	iimp 1pl	entrouvrions
_	spre 1pl	entrouvrions
_	iimp 2pl	entrouvriez
_	spre 2pl	entrouvriez
_	iimp 3pl	entrouvraient
_	ipsi 1sg	entrouvris
_	ipsi 2sg	entrouvris
_	ipsi 3sg	entrouvrit
_	ipsi 1pl	entrouvrîmes
_	ipsi 2pl	entrouvrîtes
_	ipsi 3pl	entrouvrirent
_	ifut 1sg	entrouvrirai
_	ifut 2sg	entrouvriras
_	ifut 3sg	entrouvrira
_	ifut 1pl	entrouvrirons
_	ifut 2pl	entrouvrirez
_	ifut 3pl	entrouvriront
_	cond 1sg	entrouvrirais
_	cond 2sg	entrouvrirais
_	cond 3sg	entrouvrirait
_	cond 1pl	entrouvririons
_	cond 2pl	entrouvririez
_	cond 3pl	entrouvriraient
_	simp 1sg	entrouvrisse
_	simp 2sg	entrouvrisses
_	simp 3sg	entrouvrît
_	simp 1pl	entrouvrissions
_	simp 2pl	entrouvrissiez
_	simp 3pl	entrouvrissent
_	impe 2sg	entrouvre
_	impe 1pl	entrouvrons
_	impe 2pl	entrouvrez
$
entuber	1__t___zz
_	infi	entuber
_	ppre	entubant
_	ipre 1sg	entube
_	ipre 3sg	entube
_	spre 1sg	entube
................................................................................
_	impe 1pl	nantissons
_	impe 2pl	nantissez
_	ppas mas sg	nanti
_	ppas mas pl	nantis
_	ppas fem sg	nantie
_	ppas fem pl	nanties
$
napalmer	1_it____a
_	infi	napalmer
_	ppre	napalmant
_	ipre 1sg	napalme
_	ipre 3sg	napalme
_	spre 1sg	napalme
_	spre 3sg	napalme
_	ipre 1isg	napalmè
_	ipre 2sg	napalmes
_	spre 2sg	napalmes
_	ipre 1pl	napalmons
_	ipre 2pl	napalmez
_	ipre 3pl	napalment
_	spre 3pl	napalment
_	iimp 1sg	napalmais
_	iimp 2sg	napalmais
_	iimp 3sg	napalmait
_	iimp 1pl	napalmions
_	spre 1pl	napalmions
_	iimp 2pl	napalmiez
_	spre 2pl	napalmiez
_	iimp 3pl	napalmaient
_	ipsi 1sg	napalmai
_	ipsi 2sg	napalmas
_	ipsi 3sg	napalma
_	ipsi 1pl	napalmâmes
_	ipsi 2pl	napalmâtes
_	ipsi 3pl	napalmèrent
_	ifut 1sg	napalmerai
_	ifut 2sg	napalmeras
_	ifut 3sg	napalmera
_	ifut 1pl	napalmerons
_	ifut 2pl	napalmerez
_	ifut 3pl	napalmeront
_	cond 1sg	napalmerais
_	cond 2sg	napalmerais
_	cond 3sg	napalmerait
_	cond 1pl	napalmerions
_	cond 2pl	napalmeriez
_	cond 3pl	napalmeraient
_	simp 1sg	napalmasse
_	simp 2sg	napalmasses
_	simp 3sg	napalmât
_	simp 1pl	napalmassions
_	simp 2pl	napalmassiez
_	simp 3pl	napalmassent
_	impe 2sg	napalme
_	impe 1pl	napalmons
_	impe 2pl	napalmez
_	ppas mas sg	napalmé
_	ppas mas pl	napalmés
_	ppas fem sg	napalmée
_	ppas fem pl	napalmées
$
napper	1__t___zz
_	infi	napper
_	ppre	nappant
_	ipre 1sg	nappe
_	ipre 3sg	nappe
_	spre 1sg	nappe
_	spre 3sg	nappe
................................................................................
_	impe 1pl	normalisons
_	impe 2pl	normalisez
_	ppas mas sg	normalisé
_	ppas mas pl	normalisés
_	ppas fem sg	normalisée
_	ppas fem pl	normalisées
$
normer	1_it____a
_	infi	normer
_	ppre	normant
_	ipre 1sg	norme
_	ipre 3sg	norme
_	spre 1sg	norme
_	spre 3sg	norme
_	ipre 1isg	normè
_	ipre 2sg	normes
_	spre 2sg	normes
_	ipre 1pl	normons
_	ipre 2pl	normez
_	ipre 3pl	norment
_	spre 3pl	norment
_	iimp 1sg	normais
_	iimp 2sg	normais
_	iimp 3sg	normait
_	iimp 1pl	normions
_	spre 1pl	normions
_	iimp 2pl	normiez
_	spre 2pl	normiez
_	iimp 3pl	normaient
_	ipsi 1sg	normai
_	ipsi 2sg	normas
_	ipsi 3sg	norma
_	ipsi 1pl	normâmes
_	ipsi 2pl	normâtes
_	ipsi 3pl	normèrent
_	ifut 1sg	normerai
_	ifut 2sg	normeras
_	ifut 3sg	normera
_	ifut 1pl	normerons
_	ifut 2pl	normerez
_	ifut 3pl	normeront
_	cond 1sg	normerais
_	cond 2sg	normerais
_	cond 3sg	normerait
_	cond 1pl	normerions
_	cond 2pl	normeriez
_	cond 3pl	normeraient
_	simp 1sg	normasse
_	simp 2sg	normasses
_	simp 3sg	normât
_	simp 1pl	normassions
_	simp 2pl	normassiez
_	simp 3pl	normassent
_	impe 2sg	norme
_	impe 1pl	normons
_	impe 2pl	normez
_	ppas mas sg	normé
_	ppas mas pl	normés
_	ppas fem sg	normée
_	ppas fem pl	normées
$
noter	1_it____a
_	infi	noter
_	ppre	notant
_	ipre 1sg	note
_	ipre 3sg	note
_	spre 1sg	note
_	spre 3sg	note
................................................................................
_	impe 1pl	patentons
_	impe 2pl	patentez
_	ppas mas sg	patenté
_	ppas mas pl	patentés
_	ppas fem sg	patentée
_	ppas fem pl	patentées
$
pathologiser	1_it____a
_	infi	pathologiser
_	ppre	pathologisant
_	ipre 1sg	pathologise
_	ipre 3sg	pathologise
_	spre 1sg	pathologise
_	spre 3sg	pathologise
_	ipre 1isg	pathologisè
_	ipre 2sg	pathologises
_	spre 2sg	pathologises
_	ipre 1pl	pathologisons
_	ipre 2pl	pathologisez
_	ipre 3pl	pathologisent
_	spre 3pl	pathologisent
_	iimp 1sg	pathologisais
_	iimp 2sg	pathologisais
_	iimp 3sg	pathologisait
_	iimp 1pl	pathologisions
_	spre 1pl	pathologisions
_	iimp 2pl	pathologisiez
_	spre 2pl	pathologisiez
_	iimp 3pl	pathologisaient
_	ipsi 1sg	pathologisai
_	ipsi 2sg	pathologisas
_	ipsi 3sg	pathologisa
_	ipsi 1pl	pathologisâmes
_	ipsi 2pl	pathologisâtes
_	ipsi 3pl	pathologisèrent
_	ifut 1sg	pathologiserai
_	ifut 2sg	pathologiseras
_	ifut 3sg	pathologisera
_	ifut 1pl	pathologiserons
_	ifut 2pl	pathologiserez
_	ifut 3pl	pathologiseront
_	cond 1sg	pathologiserais
_	cond 2sg	pathologiserais
_	cond 3sg	pathologiserait
_	cond 1pl	pathologiserions
_	cond 2pl	pathologiseriez
_	cond 3pl	pathologiseraient
_	simp 1sg	pathologisasse
_	simp 2sg	pathologisasses
_	simp 3sg	pathologisât
_	simp 1pl	pathologisassions
_	simp 2pl	pathologisassiez
_	simp 3pl	pathologisassent
_	impe 2sg	pathologise
_	impe 1pl	pathologisons
_	impe 2pl	pathologisez
_	ppas mas sg	pathologisé
_	ppas mas pl	pathologisés
_	ppas fem sg	pathologisée
_	ppas fem pl	pathologisées
$
patienter	1_i____zz
_	infi	patienter
_	ppre	patientant
_	ipre 1sg	patiente
_	ipre 3sg	patiente
_	spre 1sg	patiente
_	spre 3sg	patiente
................................................................................
_	impe 1pl	réattribuons
_	impe 2pl	réattribuez
_	ppas mas sg	réattribué
_	ppas mas pl	réattribués
_	ppas fem sg	réattribuée
_	ppas fem pl	réattribuées
$
réaxer	1__t_q__a
_	infi	réaxer
_	ppre	réaxant
_	ipre 1sg	réaxe
_	ipre 3sg	réaxe
_	spre 1sg	réaxe
_	spre 3sg	réaxe
_	ipre 1isg	réaxè
_	ipre 2sg	réaxes
_	spre 2sg	réaxes
_	ipre 1pl	réaxons
_	ipre 2pl	réaxez
_	ipre 3pl	réaxent
_	spre 3pl	réaxent
_	iimp 1sg	réaxais
_	iimp 2sg	réaxais
_	iimp 3sg	réaxait
_	iimp 1pl	réaxions
_	spre 1pl	réaxions
_	iimp 2pl	réaxiez
_	spre 2pl	réaxiez
_	iimp 3pl	réaxaient
_	ipsi 1sg	réaxai
_	ipsi 2sg	réaxas
_	ipsi 3sg	réaxa
_	ipsi 1pl	réaxâmes
_	ipsi 2pl	réaxâtes
_	ipsi 3pl	réaxèrent
_	ifut 1sg	réaxerai
_	ifut 2sg	réaxeras
_	ifut 3sg	réaxera
_	ifut 1pl	réaxerons
_	ifut 2pl	réaxerez
_	ifut 3pl	réaxeront
_	cond 1sg	réaxerais
_	cond 2sg	réaxerais
_	cond 3sg	réaxerait
_	cond 1pl	réaxerions
_	cond 2pl	réaxeriez
_	cond 3pl	réaxeraient
_	simp 1sg	réaxasse
_	simp 2sg	réaxasses
_	simp 3sg	réaxât
_	simp 1pl	réaxassions
_	simp 2pl	réaxassiez
_	simp 3pl	réaxassent
_	impe 2sg	réaxe
_	impe 1pl	réaxons
_	impe 2pl	réaxez
_	ppas mas sg	réaxé
_	ppas mas pl	réaxés
_	ppas fem sg	réaxée
_	ppas fem pl	réaxées
$
rebaisser	1_i____zz
_	infi	rebaisser
_	ppre	rebaissant
_	ipre 1sg	rebaisse
_	ipre 3sg	rebaisse
_	spre 1sg	rebaisse
_	spre 3sg	rebaisse
................................................................................
_	simp 1pl	réentendissions
_	simp 2pl	réentendissiez
_	simp 3pl	réentendissent
_	impe 2sg	réentends
_	impe 1pl	réentendons
_	impe 2pl	réentendez
$
réépouser	1_it____a
_	infi	réépouser
_	ppre	réépousant
_	ipre 1sg	réépouse
_	ipre 3sg	réépouse
_	spre 1sg	réépouse
_	spre 3sg	réépouse
_	ipre 1isg	réépousè
_	ipre 2sg	réépouses
_	spre 2sg	réépouses
_	ipre 1pl	réépousons
_	ipre 2pl	réépousez
_	ipre 3pl	réépousent
_	spre 3pl	réépousent
_	iimp 1sg	réépousais
_	iimp 2sg	réépousais
_	iimp 3sg	réépousait
_	iimp 1pl	réépousions
_	spre 1pl	réépousions
_	iimp 2pl	réépousiez
_	spre 2pl	réépousiez
_	iimp 3pl	réépousaient
_	ipsi 1sg	réépousai
_	ipsi 2sg	réépousas
_	ipsi 3sg	réépousa
_	ipsi 1pl	réépousâmes
_	ipsi 2pl	réépousâtes
_	ipsi 3pl	réépousèrent
_	ifut 1sg	réépouserai
_	ifut 2sg	réépouseras
_	ifut 3sg	réépousera
_	ifut 1pl	réépouserons
_	ifut 2pl	réépouserez
_	ifut 3pl	réépouseront
_	cond 1sg	réépouserais
_	cond 2sg	réépouserais
_	cond 3sg	réépouserait
_	cond 1pl	réépouserions
_	cond 2pl	réépouseriez
_	cond 3pl	réépouseraient
_	simp 1sg	réépousasse
_	simp 2sg	réépousasses
_	simp 3sg	réépousât
_	simp 1pl	réépousassions
_	simp 2pl	réépousassiez
_	simp 3pl	réépousassent
_	impe 2sg	réépouse
_	impe 1pl	réépousons
_	impe 2pl	réépousez
_	ppas mas sg	réépousé
_	ppas mas pl	réépousés
_	ppas fem sg	réépousée
_	ppas fem pl	réépousées
$
rééquilibrer	1__t___zz
_	infi	rééquilibrer
_	ppre	rééquilibrant
_	ipre 1sg	rééquilibre
_	ipre 3sg	rééquilibre
_	spre 1sg	rééquilibre
_	spre 3sg	rééquilibre
................................................................................
_	impe 1pl	rehaussons
_	impe 2pl	rehaussez
_	ppas mas sg	rehaussé
_	ppas mas pl	rehaussés
_	ppas fem sg	rehaussée
_	ppas fem pl	rehaussées
$
réhumaniser	1_it_q__a
_	infi	réhumaniser
_	ppre	réhumanisant
_	ipre 1sg	réhumanise
_	ipre 3sg	réhumanise
_	spre 1sg	réhumanise
_	spre 3sg	réhumanise
_	ipre 1isg	réhumanisè
_	ipre 2sg	réhumanises
_	spre 2sg	réhumanises
_	ipre 1pl	réhumanisons
_	ipre 2pl	réhumanisez
_	ipre 3pl	réhumanisent
_	spre 3pl	réhumanisent
_	iimp 1sg	réhumanisais
_	iimp 2sg	réhumanisais
_	iimp 3sg	réhumanisait
_	iimp 1pl	réhumanisions
_	spre 1pl	réhumanisions
_	iimp 2pl	réhumanisiez
_	spre 2pl	réhumanisiez
_	iimp 3pl	réhumanisaient
_	ipsi 1sg	réhumanisai
_	ipsi 2sg	réhumanisas
_	ipsi 3sg	réhumanisa
_	ipsi 1pl	réhumanisâmes
_	ipsi 2pl	réhumanisâtes
_	ipsi 3pl	réhumanisèrent
_	ifut 1sg	réhumaniserai
_	ifut 2sg	réhumaniseras
_	ifut 3sg	réhumanisera
_	ifut 1pl	réhumaniserons
_	ifut 2pl	réhumaniserez
_	ifut 3pl	réhumaniseront
_	cond 1sg	réhumaniserais
_	cond 2sg	réhumaniserais
_	cond 3sg	réhumaniserait
_	cond 1pl	réhumaniserions
_	cond 2pl	réhumaniseriez
_	cond 3pl	réhumaniseraient
_	simp 1sg	réhumanisasse
_	simp 2sg	réhumanisasses
_	simp 3sg	réhumanisât
_	simp 1pl	réhumanisassions
_	simp 2pl	réhumanisassiez
_	simp 3pl	réhumanisassent
_	impe 2sg	réhumanise
_	impe 1pl	réhumanisons
_	impe 2pl	réhumanisez
_	ppas mas sg	réhumanisé
_	ppas mas pl	réhumanisés
_	ppas fem sg	réhumanisée
_	ppas fem pl	réhumanisées
$
réhydrater	1__t___zz
_	infi	réhydrater
_	ppre	réhydratant
_	ipre 1sg	réhydrate
_	ipre 3sg	réhydrate
_	spre 1sg	réhydrate
_	spre 3sg	réhydrate
................................................................................
_	impe 1pl	réinvitons
_	impe 2pl	réinvitez
_	ppas mas sg	réinvité
_	ppas mas pl	réinvités
_	ppas fem sg	réinvitée
_	ppas fem pl	réinvitées
$
réislamiser	1_it_q__a
_	infi	réislamiser
_	ppre	réislamisant
_	ipre 1sg	réislamise
_	ipre 3sg	réislamise
_	spre 1sg	réislamise
_	spre 3sg	réislamise
_	ipre 1isg	réislamisè
_	ipre 2sg	réislamises
_	spre 2sg	réislamises
_	ipre 1pl	réislamisons
_	ipre 2pl	réislamisez
_	ipre 3pl	réislamisent
_	spre 3pl	réislamisent
_	iimp 1sg	réislamisais
_	iimp 2sg	réislamisais
_	iimp 3sg	réislamisait
_	iimp 1pl	réislamisions
_	spre 1pl	réislamisions
_	iimp 2pl	réislamisiez
_	spre 2pl	réislamisiez
_	iimp 3pl	réislamisaient
_	ipsi 1sg	réislamisai
_	ipsi 2sg	réislamisas
_	ipsi 3sg	réislamisa
_	ipsi 1pl	réislamisâmes
_	ipsi 2pl	réislamisâtes
_	ipsi 3pl	réislamisèrent
_	ifut 1sg	réislamiserai
_	ifut 2sg	réislamiseras
_	ifut 3sg	réislamisera
_	ifut 1pl	réislamiserons
_	ifut 2pl	réislamiserez
_	ifut 3pl	réislamiseront
_	cond 1sg	réislamiserais
_	cond 2sg	réislamiserais
_	cond 3sg	réislamiserait
_	cond 1pl	réislamiserions
_	cond 2pl	réislamiseriez
_	cond 3pl	réislamiseraient
_	simp 1sg	réislamisasse
_	simp 2sg	réislamisasses
_	simp 3sg	réislamisât
_	simp 1pl	réislamisassions
_	simp 2pl	réislamisassiez
_	simp 3pl	réislamisassent
_	impe 2sg	réislamise
_	impe 1pl	réislamisons
_	impe 2pl	réislamisez
_	ppas mas sg	réislamisé
_	ppas mas pl	réislamisés
_	ppas fem sg	réislamisée
_	ppas fem pl	réislamisées
$
réitérer	1_it___zz
_	infi	réitérer
_	ppre	réitérant
_	ipre 1sg	réitère
_	ipre 3sg	réitère
_	spre 1sg	réitère
_	spre 3sg	réitère
................................................................................
_	impe 1pl	rescindons
_	impe 2pl	rescindez
_	ppas mas sg	rescindé
_	ppas mas pl	rescindés
_	ppas fem sg	rescindée
_	ppas fem pl	rescindées
$
rescolariser	1_it____a
_	infi	rescolariser
_	ppre	rescolarisant
_	ipre 1sg	rescolarise
_	ipre 3sg	rescolarise
_	spre 1sg	rescolarise
_	spre 3sg	rescolarise
_	ipre 1isg	rescolarisè
_	ipre 2sg	rescolarises
_	spre 2sg	rescolarises
_	ipre 1pl	rescolarisons
_	ipre 2pl	rescolarisez
_	ipre 3pl	rescolarisent
_	spre 3pl	rescolarisent
_	iimp 1sg	rescolarisais
_	iimp 2sg	rescolarisais
_	iimp 3sg	rescolarisait
_	iimp 1pl	rescolarisions
_	spre 1pl	rescolarisions
_	iimp 2pl	rescolarisiez
_	spre 2pl	rescolarisiez
_	iimp 3pl	rescolarisaient
_	ipsi 1sg	rescolarisai
_	ipsi 2sg	rescolarisas
_	ipsi 3sg	rescolarisa
_	ipsi 1pl	rescolarisâmes
_	ipsi 2pl	rescolarisâtes
_	ipsi 3pl	rescolarisèrent
_	ifut 1sg	rescolariserai
_	ifut 2sg	rescolariseras
_	ifut 3sg	rescolarisera
_	ifut 1pl	rescolariserons
_	ifut 2pl	rescolariserez
_	ifut 3pl	rescolariseront
_	cond 1sg	rescolariserais
_	cond 2sg	rescolariserais
_	cond 3sg	rescolariserait
_	cond 1pl	rescolariserions
_	cond 2pl	rescolariseriez
_	cond 3pl	rescolariseraient
_	simp 1sg	rescolarisasse
_	simp 2sg	rescolarisasses
_	simp 3sg	rescolarisât
_	simp 1pl	rescolarisassions
_	simp 2pl	rescolarisassiez
_	simp 3pl	rescolarisassent
_	impe 2sg	rescolarise
_	impe 1pl	rescolarisons
_	impe 2pl	rescolarisez
_	ppas mas sg	rescolarisé
_	ppas mas pl	rescolarisés
_	ppas fem sg	rescolarisée
_	ppas fem pl	rescolarisées
$
réseauter	1_i____zz
_	infi	réseauter
_	ppre	réseautant
_	ipre 1sg	réseaute
_	ipre 3sg	réseaute
_	spre 1sg	réseaute
_	spre 3sg	réseaute
................................................................................
_	impe 1pl	resocialisons
_	impe 2pl	resocialisez
_	ppas mas sg	resocialisé
_	ppas mas pl	resocialisés
_	ppas fem sg	resocialisée
_	ppas fem pl	resocialisées
$
resolidifier	1_it_q__a
_	infi	resolidifier
_	ppre	resolidifiant
_	ipre 1sg	resolidifie
_	ipre 3sg	resolidifie
_	spre 1sg	resolidifie
_	spre 3sg	resolidifie
_	ipre 1isg	resolidifiè
_	ipre 2sg	resolidifies
_	spre 2sg	resolidifies
_	ipre 1pl	resolidifions
_	ipre 2pl	resolidifiez
_	ipre 3pl	resolidifient
_	spre 3pl	resolidifient
_	iimp 1sg	resolidifiais
_	iimp 2sg	resolidifiais
_	iimp 3sg	resolidifiait
_	iimp 1pl	resolidifiions
_	spre 1pl	resolidifiions
_	iimp 2pl	resolidifiiez
_	spre 2pl	resolidifiiez
_	iimp 3pl	resolidifiaient
_	ipsi 1sg	resolidifiai
_	ipsi 2sg	resolidifias
_	ipsi 3sg	resolidifia
_	ipsi 1pl	resolidifiâmes
_	ipsi 2pl	resolidifiâtes
_	ipsi 3pl	resolidifièrent
_	ifut 1sg	resolidifierai
_	ifut 2sg	resolidifieras
_	ifut 3sg	resolidifiera
_	ifut 1pl	resolidifierons
_	ifut 2pl	resolidifierez
_	ifut 3pl	resolidifieront
_	cond 1sg	resolidifierais
_	cond 2sg	resolidifierais
_	cond 3sg	resolidifierait
_	cond 1pl	resolidifierions
_	cond 2pl	resolidifieriez
_	cond 3pl	resolidifieraient
_	simp 1sg	resolidifiasse
_	simp 2sg	resolidifiasses
_	simp 3sg	resolidifiât
_	simp 1pl	resolidifiassions
_	simp 2pl	resolidifiassiez
_	simp 3pl	resolidifiassent
_	impe 2sg	resolidifie
_	impe 1pl	resolidifions
_	impe 2pl	resolidifiez
_	ppas mas sg	resolidifié
_	ppas mas pl	resolidifiés
_	ppas fem sg	resolidifiée
_	ppas fem pl	resolidifiées
$
résonner	1_i____zz
_	infi	résonner
_	ppre	résonnant
_	ipre 1sg	résonne
_	ipre 3sg	résonne
_	spre 1sg	résonne
_	spre 3sg	résonne
................................................................................
_	impe 1pl	rythmons
_	impe 2pl	rythmez
_	ppas mas sg	rythmé
_	ppas mas pl	rythmés
_	ppas fem sg	rythmée
_	ppas fem pl	rythmées
$



sabler	1_it___zz
_	infi	sabler
_	ppre	sablant
_	ipre 1sg	sable
_	ipre 3sg	sable
_	spre 1sg	sable
_	spre 3sg	sable
................................................................................
_	impe 1pl	sabrons
_	impe 2pl	sabrez
_	ppas mas sg	sabré
_	ppas mas pl	sabrés
_	ppas fem sg	sabrée
_	ppas fem pl	sabrées
$



sacagner	1__t___zz
_	infi	sacagner
_	ppre	sacagnant
_	ipre 1sg	sacagne
_	ipre 3sg	sacagne
_	spre 1sg	sacagne
_	spre 3sg	sacagne
................................................................................
_	impe 1pl	safranons
_	impe 2pl	safranez
_	ppas mas sg	safrané
_	ppas mas pl	safranés
_	ppas fem sg	safranée
_	ppas fem pl	safranées
$










saietter	1__t___zz
_	infi	saietter
_	ppre	saiettant
_	ipre 1sg	saiette
_	ipre 3sg	saiette
_	spre 1sg	saiette
_	spre 3sg	saiette
................................................................................
_	impe 1pl	solidarisons
_	impe 2pl	solidarisez
_	ppas mas sg	solidarisé
_	ppas mas pl	solidarisés
_	ppas fem sg	solidarisée
_	ppas fem pl	solidarisées
$
solidifier	1_it_q__a
_	infi	solidifier
_	ppre	solidifiant
_	ipre 1sg	solidifie
_	ipre 3sg	solidifie
_	spre 1sg	solidifie
_	spre 3sg	solidifie
_	ipre 1isg	solidifiè
................................................................................
_	simp 1pl	sursissions
_	simp 2pl	sursissiez
_	simp 3pl	sursissent
_	impe 2sg	sursois
_	impe 1pl	sursoyons
_	impe 2pl	sursoyez
$
sursolliciter	1_it_q__a
_	infi	sursolliciter
_	ppre	sursollicitant
_	ipre 1sg	sursollicite
_	ipre 3sg	sursollicite
_	spre 1sg	sursollicite
_	spre 3sg	sursollicite
_	ipre 1isg	sursollicitè
_	ipre 2sg	sursollicites
_	spre 2sg	sursollicites
_	ipre 1pl	sursollicitons
_	ipre 2pl	sursollicitez
_	ipre 3pl	sursollicitent
_	spre 3pl	sursollicitent
_	iimp 1sg	sursollicitais
_	iimp 2sg	sursollicitais
_	iimp 3sg	sursollicitait
_	iimp 1pl	sursollicitions
_	spre 1pl	sursollicitions
_	iimp 2pl	sursollicitiez
_	spre 2pl	sursollicitiez
_	iimp 3pl	sursollicitaient
_	ipsi 1sg	sursollicitai
_	ipsi 2sg	sursollicitas
_	ipsi 3sg	sursollicita
_	ipsi 1pl	sursollicitâmes
_	ipsi 2pl	sursollicitâtes
_	ipsi 3pl	sursollicitèrent
_	ifut 1sg	sursolliciterai
_	ifut 2sg	sursolliciteras
_	ifut 3sg	sursollicitera
_	ifut 1pl	sursolliciterons
_	ifut 2pl	sursolliciterez
_	ifut 3pl	sursolliciteront
_	cond 1sg	sursolliciterais
_	cond 2sg	sursolliciterais
_	cond 3sg	sursolliciterait
_	cond 1pl	sursolliciterions
_	cond 2pl	sursolliciteriez
_	cond 3pl	sursolliciteraient
_	simp 1sg	sursollicitasse
_	simp 2sg	sursollicitasses
_	simp 3sg	sursollicitât
_	simp 1pl	sursollicitassions
_	simp 2pl	sursollicitassiez
_	simp 3pl	sursollicitassent
_	impe 2sg	sursollicite
_	impe 1pl	sursollicitons
_	impe 2pl	sursollicitez
_	ppas mas sg	sursollicité
_	ppas mas pl	sursollicités
_	ppas fem sg	sursollicitée
_	ppas fem pl	sursollicitées
$
sursouffler	1__t___zz
_	infi	sursouffler
_	ppre	sursoufflant
_	ipre 1sg	sursouffle
_	ipre 3sg	sursouffle
_	spre 1sg	sursouffle
_	spre 3sg	sursouffle
................................................................................
_	impe 2sg	systématise
_	impe 1pl	systématisons
_	impe 2pl	systématisez
_	ppas mas sg	systématisé
_	ppas mas pl	systématisés
_	ppas fem sg	systématisée
_	ppas fem pl	systématisées
$
s’abader	1____p_e_
_	infi	s’abader
$
s’abriller	1____p_e_
_	infi	s’abriller
$
s’agir	2____p_e_
_	infi	s’agir
_	ppre	s’agissant
_	ipre 3sg	s’agit
_	iimp 3sg	s’agissait
_	ifut 3sg	s’agira
_	cond 3sg	s’agirait
_	spre 3sg	s’agisse
_	simp 3sg	s’agît
$
tabasser	1__t_q_zz
_	infi	tabasser
_	ppre	tabassant
_	ipre 1sg	tabasse
_	ipre 3sg	tabasse
_	spre 1sg	tabasse
................................................................................
_	impe 1pl	transitons
_	impe 2pl	transitez
_	ppas mas sg	transité
_	ppas mas pl	transités
_	ppas fem sg	transitée
_	ppas fem pl	transitées
$
transitionner	1_i_____a
_	infi	transitionner
_	ppre	transitionnant
_	ipre 1sg	transitionne
_	ipre 3sg	transitionne
_	spre 1sg	transitionne
_	spre 3sg	transitionne
_	ipre 1isg	transitionnè
_	ipre 2sg	transitionnes
_	spre 2sg	transitionnes
_	ipre 1pl	transitionnons
_	ipre 2pl	transitionnez
_	ipre 3pl	transitionnent
_	spre 3pl	transitionnent
_	iimp 1sg	transitionnais
_	iimp 2sg	transitionnais
_	iimp 3sg	transitionnait
_	iimp 1pl	transitionnions
_	spre 1pl	transitionnions
_	iimp 2pl	transitionniez
_	spre 2pl	transitionniez
_	iimp 3pl	transitionnaient
_	ipsi 1sg	transitionnai
_	ipsi 2sg	transitionnas
_	ipsi 3sg	transitionna
_	ipsi 1pl	transitionnâmes
_	ipsi 2pl	transitionnâtes
_	ipsi 3pl	transitionnèrent
_	ifut 1sg	transitionnerai
_	ifut 2sg	transitionneras
_	ifut 3sg	transitionnera
_	ifut 1pl	transitionnerons
_	ifut 2pl	transitionnerez
_	ifut 3pl	transitionneront
_	cond 1sg	transitionnerais
_	cond 2sg	transitionnerais
_	cond 3sg	transitionnerait
_	cond 1pl	transitionnerions
_	cond 2pl	transitionneriez
_	cond 3pl	transitionneraient
_	simp 1sg	transitionnasse
_	simp 2sg	transitionnasses
_	simp 3sg	transitionnât
_	simp 1pl	transitionnassions
_	simp 2pl	transitionnassiez
_	simp 3pl	transitionnassent
_	impe 2sg	transitionne
_	impe 1pl	transitionnons
_	impe 2pl	transitionnez
_	ppas mas sg	transitionné
_	ppas mas pl	transitionnés
_	ppas fem sg	transitionnée
_	ppas fem pl	transitionnées
$
translater	1__t___zz
_	infi	translater
_	ppre	translatant
_	ipre 1sg	translate
_	ipre 3sg	translate
_	spre 1sg	translate
_	spre 3sg	translate
................................................................................
_	simp 2pl	zonzonnassiez
_	simp 3pl	zonzonnassent
_	impe 2sg	zonzonne
_	impe 1pl	zonzonnons
_	impe 2pl	zonzonnez
_	ppas epi inv	zonzonné
$
zoomer	1_it____a
_	infi	zoomer
_	ppre	zoomant
_	ipre 1sg	zoome
_	ipre 3sg	zoome
_	spre 1sg	zoome
_	spre 3sg	zoome
_	ipre 1isg	zoomè

Modified gc_lang/fr/data/dictDecl.txt from [25562f3d4d] to [3a7a8fac4c].

342
343
344
345
346
347
348




349
350
351
352
353
354
355
....
1357
1358
1359
1360
1361
1362
1363






1364
1365
1366
1367
1368
1369
1370
....
3184
3185
3186
3187
3188
3189
3190




3191
3192
3193
3194
3195
3196
3197
....
3300
3301
3302
3303
3304
3305
3306




3307
3308
3309
3310
3311
3312
3313
.....
14273
14274
14275
14276
14277
14278
14279




14280
14281
14282
14283
14284
14285
14286
.....
16386
16387
16388
16389
16390
16391
16392




16393
16394
16395
16396
16397
16398
16399
.....
20971
20972
20973
20974
20975
20976
20977




20978
20979
20980
20981
20982
20983
20984
.....
21591
21592
21593
21594
21595
21596
21597




21598
21599
21600
21601
21602
21603
21604
.....
21961
21962
21963
21964
21965
21966
21967




21968
21969
21970
21971
21972
21973
21974
.....
22504
22505
22506
22507
22508
22509
22510




22511
22512
22513
22514
22515
22516
22517
.....
22735
22736
22737
22738
22739
22740
22741




22742
22743
22744
22745
22746
22747
22748
.....
23535
23536
23537
23538
23539
23540
23541
23542
23543
23544
23545
23546
23547
23548
23549
23550
23551
23552
23553
23554
23555
23556
23557
23558
23559
23560
23561
23562
23563
23564
23565
23566
23567










23568
23569
23570
23571
23572
23573
23574
.....
27433
27434
27435
27436
27437
27438
27439




27440
27441
27442
27443
27444
27445
27446
.....
30604
30605
30606
30607
30608
30609
30610




30611
30612
30613
30614
30615
30616
30617
.....
32389
32390
32391
32392
32393
32394
32395




32396
32397
32398
32399
32400
32401
32402
.....
33575
33576
33577
33578
33579
33580
33581




33582
33583
33584
33585
33586
33587
33588
.....
34166
34167
34168
34169
34170
34171
34172




34173
34174
34175
34176
34177
34178
34179
.....
34578
34579
34580
34581
34582
34583
34584




34585
34586
34587
34588
34589
34590
34591
.....
36680
36681
36682
36683
36684
36685
36686




36687
36688
36689
36690
36691
36692
36693
.....
44371
44372
44373
44374
44375
44376
44377




44378
44379
44380
44381
44382
44383
44384
.....
45038
45039
45040
45041
45042
45043
45044




45045
45046
45047
45048
45049
45050
45051
.....
47597
47598
47599
47600
47601
47602
47603
47604
47605
47606
47607
47608
47609
47610
47611
47612
47613
47614
.....
47691
47692
47693
47694
47695
47696
47697




47698
47699
47700
47701
47702
47703
47704
.....
55906
55907
55908
55909
55910
55911
55912




55913
55914
55915
55916
55917
55918
55919
.....
58272
58273
58274
58275
58276
58277
58278






58279
58280
58281
58282
58283
58284
58285
.....
58807
58808
58809
58810
58811
58812
58813




58814
58815
58816
58817
58818
58819
58820
.....
64705
64706
64707
64708
64709
64710
64711




64712
64713
64714
64715
64716
64717
64718
.....
65350
65351
65352
65353
65354
65355
65356




65357
65358
65359
65360
65361
65362
65363
.....
66284
66285
66286
66287
66288
66289
66290




66291
66292
66293
66294
66295
66296
66297
.....
67153
67154
67155
67156
67157
67158
67159




67160
67161
67162
67163
67164
67165
67166
.....
68734
68735
68736
68737
68738
68739
68740




68741
68742
68743
68744
68745
68746
68747
.....
70350
70351
70352
70353
70354
70355
70356






70357
70358
70359
70360
70361
70362
70363
.....
70568
70569
70570
70571
70572
70573
70574




70575
70576
70577
70578
70579
70580
70581
.....
77021
77022
77023
77024
77025
77026
77027






77028
77029
77030
77031
77032
77033
77034
.....
78304
78305
78306
78307
78308
78309
78310
78311
78312
78313
78314
78315
78316
78317
78318
78319
78320
78321
78322
78323
78324
.....
80441
80442
80443
80444
80445
80446
80447




80448
80449
80450
80451
80452
80453
80454
.....
82359
82360
82361
82362
82363
82364
82365








82366
82367
82368
82369
82370
82371
82372
.....
90919
90920
90921
90922
90923
90924
90925




90926
90927
90928
90929
90930
90931
90932
.....
93372
93373
93374
93375
93376
93377
93378




93379
93380
93381
93382
93383
93384
93385
.....
94615
94616
94617
94618
94619
94620
94621
94622
94623
94624

94625
94626
94627
94628
94629
94630
94631
.....
98321
98322
98323
98324
98325
98326
98327
98328
98329
98330
98331
98332
98333
98334
98335
98336
98337
98338
......
105939
105940
105941
105942
105943
105944
105945






105946
105947
105948
105949
105950
105951
105952
......
109919
109920
109921
109922
109923
109924
109925




109926
109927
109928
109929
109930
109931
109932
......
110981
110982
110983
110984
110985
110986
110987




110988
110989
110990
110991
110992
110993
110994
......
114705
114706
114707
114708
114709
114710
114711




114712
114713
114714
114715
114716
114717
114718
......
116694
116695
116696
116697
116698
116699
116700




116701
116702
116703
116704
116705
116706
116707
......
120007
120008
120009
120010
120011
120012
120013




120014
120015
120016
120017
120018
120019
120020
......
120027
120028
120029
120030
120031
120032
120033




120034
120035
120036
120037
120038
120039
120040
......
120310
120311
120312
120313
120314
120315
120316




120317
120318
120319
120320
120321
120322
120323
......
120342
120343
120344
120345
120346
120347
120348




120349
120350
120351
120352
120353
120354
120355
......
123112
123113
123114
123115
123116
123117
123118




123119
123120
123121
123122
123123
123124
123125
......
123623
123624
123625
123626
123627
123628
123629




123630
123631
123632
123633
123634
123635
123636
......
125279
125280
125281
125282
125283
125284
125285






125286
125287
125288
125289
125290
125291
125292
......
133527
133528
133529
133530
133531
133532
133533




133534
133535
133536
133537
133538
133539
133540
......
133990
133991
133992
133993
133994
133995
133996
133997
133998
133999
134000
134001
134002
134003
134004
134005
134006
134007
134008
134009
134010
134011
134012
134013
134014
134015
134016
134017
134018
......
135108
135109
135110
135111
135112
135113
135114
135115
135116
135117
135118
135119
135120
135121
135122
135123
135124
135125
135126








135127
135128
135129
135130
135131
135132
135133
......
144544
144545
144546
144547
144548
144549
144550




144551
144552
144553
144554
144555
144556
144557
......
146027
146028
146029
146030
146031
146032
146033
146034
146035
146036
146037
146038
146039
146040
146041




146042
146043
146044
146045
146046
146047
146048
146049
146050
146051
......
147088
147089
147090
147091
147092
147093
147094




147095
147096
147097
147098
147099
147100
147101
......
149001
149002
149003
149004
149005
149006
149007





149008
149009
149010
149011
149012
149013
149014
......
151189
151190
151191
151192
151193
151194
151195




151196
151197
151198
151199
151200
151201
151202
......
151282
151283
151284
151285
151286
151287
151288






151289
151290
151291
151292
151293
151294
151295
......
153099
153100
153101
153102
153103
153104
153105




153106
153107
153108
153109
153110
153111
153112
153113




153114
153115
153116
153117
153118
153119
153120
......
156062
156063
156064
156065
156066
156067
156068




156069
156070
156071
156072
156073
156074
156075
......
162795
162796
162797
162798
162799
162800
162801




162802
162803
162804
162805
162806
162807
162808
......
162997
162998
162999
163000
163001
163002
163003








163004
163005
163006
163007
163008
163009
163010
......
169369
169370
169371
169372
169373
169374
169375




169376
169377
169378
169379
169380
169381
169382
......
172296
172297
172298
172299
172300
172301
172302






172303
172304
172305
172306
172307
172308
172309
......
175115
175116
175117
175118
175119
175120
175121




175122
175123
175124
175125
175126
175127
175128
......
177852
177853
177854
177855
177856
177857
177858




177859
177860
177861
177862
177863
177864
177865
......
178592
178593
178594
178595
178596
178597
178598




178599
178600
178601
178602
178603
178604
178605
......
180423
180424
180425
180426
180427
180428
180429
180430
180431
180432
180433
180434
180435
180436
180437
180438
180439
180440
......
183425
183426
183427
183428
183429
183430
183431




183432
183433
183434
183435
183436
183437
183438
......
187359
187360
187361
187362
187363
187364
187365




187366
187367
187368
187369
187370
187371
187372
......
192390
192391
192392
192393
192394
192395
192396




192397
192398
192399
192400
192401
192402
192403
......
192440
192441
192442
192443
192444
192445
192446




192447
192448
192449
192450
192451
192452
192453
......
192491
192492
192493
192494
192495
192496
192497
192498
192499
192500
192501
192502
192503
192504
192505
192506
192507
192508
192509
192510
192511
......
195669
195670
195671
195672
195673
195674
195675
195676
195677
195678
195679
195680
195681
195682
195683
195684
195685
195686
195687
195688
195689
195690
195691
195692
195693
195694
195695
195696
195697
195698
195699
195700
195701
195702
195703
195704
195705
195706
195707
195708
195709
195710
195711














195712
195713
195714
195715
195716
195717
195718
......
196612
196613
196614
196615
196616
196617
196618
196619
196620
196621
196622
196623
196624
196625
196626
196627
196628
196629
196630
196631
......
197540
197541
197542
197543
197544
197545
197546




197547
197548
197549
197550
197551
197552
197553
......
198006
198007
198008
198009
198010
198011
198012






198013
198014
198015
198016
198017
198018
198019
......
201736
201737
201738
201739
201740
201741
201742




201743
201744
201745
201746
201747
201748
201749
......
202581
202582
202583
202584
202585
202586
202587




202588
202589
202590
202591
202592
202593
202594
......
203627
203628
203629
203630
203631
203632
203633




203634
203635
203636
203637
203638
203639
203640
......
203690
203691
203692
203693
203694
203695
203696
203697
203698
203699
203700
203701
203702
203703
203704
203705
......
205474
205475
205476
205477
205478
205479
205480




205481
205482
205483
205484
205485
205486
205487
......
207487
207488
207489
207490
207491
207492
207493




207494
207495
207496
207497
207498
207499
207500
......
212240
212241
212242
212243
212244
212245
212246






212247
212248
212249
212250
212251
212252
212253
......
212899
212900
212901
212902
212903
212904
212905




212906
212907
212908
212909
212910
212911
212912
......
227045
227046
227047
227048
227049
227050
227051




227052
227053
227054
227055
227056
227057
227058
......
230325
230326
230327
230328
230329
230330
230331




230332
230333
230334
230335
230336
230337
230338
......
230438
230439
230440
230441
230442
230443
230444




230445
230446
230447
230448
230449
230450
230451
......
230670
230671
230672
230673
230674
230675
230676




230677
230678
230679
230680
230681
230682
230683
......
233764
233765
233766
233767
233768
233769
233770




233771
233772
233773
233774
233775
233776
233777
......
234282
234283
234284
234285
234286
234287
234288












234289
234290
234291
234292
234293
234294
234295
......
234877
234878
234879
234880
234881
234882
234883




234884
234885
234886
234887
234888
234889
234890
......
235519
235520
235521
235522
235523
235524
235525




235526
235527
235528
235529
235530
235531
235532
......
235789
235790
235791
235792
235793
235794
235795




235796
235797
235798
235799
235800
235801
235802
......
241569
241570
241571
241572
241573
241574
241575




241576
241577
241578
241579
241580
241581
241582
......
243952
243953
243954
243955
243956
243957
243958




243959
243960
243961
243962
243963
243964
243965
......
244146
244147
244148
244149
244150
244151
244152




244153
244154
244155
244156
244157
244158
244159
......
246115
246116
246117
246118
246119
246120
246121






246122
246123
246124
246125
246126
246127
246128
......
250242
250243
250244
250245
250246
250247
250248




250249
250250
250251
250252
250253
250254
250255
......
250916
250917
250918
250919
250920
250921
250922




250923
250924
250925
250926
250927
250928
250929
......
251075
251076
251077
251078
251079
251080
251081




251082
251083
251084
251085
251086
251087
251088
......
251221
251222
251223
251224
251225
251226
251227




251228
251229
251230
251231
251232
251233
251234
......
253245
253246
253247
253248
253249
253250
253251




253252
253253
253254
253255
253256
253257
253258
_	nom adj epi sg	abdicataire
_	nom adj epi pl	abdicataires
$
abdication	S*()
_	nom fem sg	abdication
_	nom fem pl	abdications
$




abdomen	S*()
_	nom mas sg	abdomen
_	nom mas pl	abdomens
$
abdominal	X*()
_	nom mas sg	abdominal
_	nom mas pl	abdominaux
................................................................................
_	adj epi sg	acathiste
_	adj epi pl	acathistes
$
acaule	S*()
_	adj epi sg	acaule
_	adj epi pl	acaules
$






accablante	F*()
_	nom adj fem sg	accablante
_	nom adj fem pl	accablantes
_	nom adj mas sg	accablant
_	nom adj mas pl	accablants
$
accablement	S*()
................................................................................
$
addictive	F*()
_	adj fem sg	addictive
_	adj fem pl	addictives
_	adj mas sg	addictif
_	adj mas pl	addictifs
$




addictologie	S*()
_	nom fem sg	addictologie
_	nom fem pl	addictologies
$
addictologique	S*()
_	adj epi sg	addictologique
_	adj epi pl	addictologiques
................................................................................
_	nom fem sg	adénomectomie
_	nom fem pl	adénomectomies
$
adénopathie	S*()
_	nom fem sg	adénopathie
_	nom fem pl	adénopathies
$




adénosine	S*()
_	nom fem sg	adénosine
_	nom fem pl	adénosines
$
adénovirale	W*()
_	adj fem sg	adénovirale
_	adj fem pl	adénovirales
................................................................................
$
antitussive	F*()
_	adj fem sg	antitussive
_	adj fem pl	antitussives
_	adj mas sg	antitussif
_	adj mas pl	antitussifs
$




antivariolique	S*()
_	adj epi sg	antivariolique
_	adj epi pl	antivarioliques
$
antivénéneuse	W*()
_	adj fem sg	antivénéneuse
_	adj fem pl	antivénéneuses
................................................................................
_	nom fem sg	archi
_	nom fem pl	archis
$
archiatre	S*()
_	nom mas sg	archiatre
_	nom mas pl	archiatres
$




archichancelier	S*()
_	nom mas sg	archichancelier
_	nom mas pl	archichanceliers
$
archiconfrérie	S*()
_	nom fem sg	archiconfrérie
_	nom fem pl	archiconfréries
................................................................................
_	adj mas sg	autocollant
_	adj mas pl	autocollants
$
autocommutateur	S*()
_	nom mas sg	autocommutateur
_	nom mas pl	autocommutateurs
$




autoconcurrence	S*()
_	nom fem sg	autoconcurrence
_	nom fem pl	autoconcurrences
$
autoconditionnement	S*()
_	nom mas sg	autoconditionnement
_	nom mas pl	autoconditionnements
................................................................................
_	nom fem sg	autopatrouille
_	nom fem pl	autopatrouilles
$
autophagie	S*()
_	nom fem sg	autophagie
_	nom fem pl	autophagies
$




autopilote	S*()
_	nom mas sg	autopilote
_	nom mas pl	autopilotes
$
autopilotée	F*()
_	adj fem sg	autopilotée
_	adj fem pl	autopilotées
................................................................................
_	nom adj mas sg	autrichien
_	nom adj mas pl	autrichiens
$
autruche	S*()
_	nom fem sg	autruche
_	nom fem pl	autruches
$




autunite	S*()
_	nom fem sg	autunite
_	nom fem pl	autunites
$
auvent	S*()
_	nom mas sg	auvent
_	nom mas pl	auvents
................................................................................
_	nom mas sg	aviron
_	nom mas pl	avirons
$
avirulence	S*()
_	nom fem sg	avirulence
_	nom fem pl	avirulences
$




aviso	S*()
_	nom mas sg	aviso
_	nom mas pl	avisos
$
avitaillement	S*()
_	nom mas sg	avitaillement
_	nom mas pl	avitaillements
................................................................................
_	adj epi sg	axonométrique
_	adj epi pl	axonométriques
$
axopode	S*()
_	nom mas sg	axopode
_	nom mas pl	axopodes
$




ayant	S*()
_	nom mas sg	ayant
_	nom mas pl	ayants
$
ayatollah	S*()
_	nom mas sg	ayatollah
_	nom mas pl	ayatollahs
................................................................................
_	nom mas sg	baguier
_	nom mas pl	baguiers
$
baguiste	S.()
_	nom epi sg	baguiste
_	nom epi pl	baguistes
$
baha'ie	F.()
_	nom adj fem sg	baha'ie
_	nom adj fem pl	baha'ies
_	nom adj mas sg	baha'i
_	nom adj mas pl	baha'is
$
bahaïe	F.()
_	nom adj fem sg	bahaïe
_	nom adj fem pl	bahaïes
_	nom adj mas sg	bahaï
_	nom adj mas pl	bahaïs
$
baha'isme	S.()
_	nom mas sg	baha'isme
_	nom mas pl	baha'ismes
$
bahaïsme	S.()
_	nom mas sg	bahaïsme
_	nom mas pl	bahaïsmes
$
bahamienne	F.()
_	nom adj fem sg	bahamienne
_	nom adj fem pl	bahamiennes
_	nom adj mas sg	bahamien
_	nom adj mas pl	bahamiens
$










bahreïnie	F.()
_	nom adj fem sg	bahreïnie
_	nom adj fem pl	bahreïnies
_	nom adj mas sg	bahreïni
_	nom adj mas pl	bahreïnis
$
baht	S.()
................................................................................
$
beugleuse	F.()
_	nom fem sg	beugleuse
_	nom fem pl	beugleuses
_	nom mas sg	beugleur
_	nom mas pl	beugleurs
$




beur	S.()
_	nom adj epi sg	beur
_	nom adj epi pl	beurs
$
beurette	S.()
_	nom fem sg	beurette
_	nom fem pl	beurettes
................................................................................
_	nom epi sg	blitzkrieg
_	nom epi pl	blitzkriegs
$
blizzard	S.()
_	nom mas sg	blizzard
_	nom mas pl	blizzards
$




bloc	S.()
_	nom mas sg	bloc
_	nom mas pl	blocs
$
blocage	S.()
_	nom mas sg	blocage
_	nom mas pl	blocages
................................................................................
_	nom fem sg	bouillasse
_	nom fem pl	bouillasses
$
bouille	S.()
_	nom fem sg	bouille
_	nom fem pl	bouilles
$




bouilleuse	F.()
_	nom fem sg	bouilleuse
_	nom fem pl	bouilleuses
_	nom mas sg	bouilleur
_	nom mas pl	bouilleurs
$
bouillie	S.()
................................................................................
_	adj epi sg	branchiopode
_	adj epi pl	branchiopodes
$
branchiopode	S.()
_	nom mas sg	branchiopode
_	nom mas pl	branchiopodes
$




branchue	F.()
_	adj fem sg	branchue
_	adj fem pl	branchues
_	adj mas sg	branchu
_	adj mas pl	branchus
$
brandade	S.()
................................................................................
_	adj mas sg	brillant
_	adj mas pl	brillants
$
brillantine	S.()
_	nom fem sg	brillantine
_	nom fem pl	brillantines
$




brimade	S.()
_	nom fem sg	brimade
_	nom fem pl	brimades
$
brimbalement	S.()
_	nom mas sg	brimbalement
_	nom mas pl	brimbalements
................................................................................
_	nom mas sg	bromoxynil
_	nom mas pl	bromoxynils
$
bromure	S.()
_	nom mas sg	bromure
_	nom mas pl	bromures
$




bronchade	S.()
_	nom fem sg	bronchade
_	nom fem pl	bronchades
$
bronche	S.()
_	nom fem sg	bronche
_	nom fem pl	bronches
................................................................................
_	nom mas sg	cadeau
_	nom mas pl	cadeaux
$
cadenassable	S.()
_	adj epi sg	cadenassable
_	adj epi pl	cadenassables
$




cadence	S.()
_	nom fem sg	cadence
_	nom fem pl	cadences
$
cadencement	S.()
_	nom mas sg	cadencement
_	nom mas pl	cadencements
................................................................................
_	nom fem sg	chapelure
_	nom fem pl	chapelures
$
chaperon	S.()
_	nom mas sg	chaperon
_	nom mas pl	chaperons
$




chapiste	S.()
_	nom epi sg	chapiste
_	nom epi pl	chapistes
$
chapiteau	X.()
_	nom mas sg	chapiteau
_	nom mas pl	chapiteaux
................................................................................
$
chatteuse	F.()
_	nom fem sg	chatteuse
_	nom fem pl	chatteuses
_	nom mas sg	chatteur
_	nom mas pl	chatteurs
$




chaude	F.()
_	nom adj fem sg	chaude
_	nom adj fem pl	chaudes
_	nom adj mas sg	chaud
_	nom adj mas pl	chauds
$
chaudeau	X.()
................................................................................
_	nom adj epi sg	chti
_	nom adj epi pl	chtis
$
chtimi	S.()
_	nom adj epi sg	chtimi
_	nom adj epi pl	chtimis
$
ch'timi	S.()
_	nom adj epi sg	ch'timi
_	nom adj epi pl	ch'timis
$
chtonienne	F.()
_	adj fem sg	chtonienne
_	adj fem pl	chtoniennes
_	adj mas sg	chtonien
_	adj mas pl	chtoniens
$
chtouille	S.()
................................................................................
_	adj mas sg	chypré
_	adj mas pl	chyprés
$
chypriote	S.()
_	nom adj epi sg	chypriote
_	nom adj epi pl	chypriotes
$




ciabatta	S.()
_	nom fem sg	ciabatta
_	nom fem pl	ciabattas
$
cibiche	S.()
_	nom fem sg	cibiche
_	nom fem pl	cibiches
................................................................................
_	nom mas sg	contour
_	nom mas pl	contours
$
contournable	S.()
_	adj epi sg	contournable
_	adj epi pl	contournables
$




contournement	S.()
_	nom mas sg	contournement
_	nom mas pl	contournements
$
contraceptif	S.()
_	nom mas sg	contraceptif
_	nom mas pl	contraceptifs
................................................................................
_	nom mas sg	coran
_	nom mas pl	corans
$
coranique	S.()
_	adj epi sg	coranique
_	adj epi pl	coraniques
$






corb	S.()
_	nom mas sg	corb
_	nom mas pl	corbs
$
corbac	S.()
_	nom mas sg	corbac
_	nom mas pl	corbacs
................................................................................
$
correcte	F.()
_	adj fem sg	correcte
_	adj fem pl	correctes
_	adj mas sg	correct
_	adj mas pl	corrects
$




correctif	S.()
_	nom mas sg	correctif
_	nom mas pl	correctifs
$
correction	S.()
_	nom fem sg	correction
_	nom fem pl	corrections
................................................................................
_	nom mas sg	damalisque
_	nom mas pl	damalisques
$
daman	S.()
_	nom mas sg	daman
_	nom mas pl	damans
$




damasquinage	S.()
_	nom mas sg	damasquinage
_	nom mas pl	damasquinages
$
damasquinerie	S.()
_	nom fem sg	damasquinerie
_	nom fem pl	damasquineries
................................................................................
_	adj epi sg	déblocable
_	adj epi pl	déblocables
$
déblocage	S.()
_	nom mas sg	déblocage
_	nom mas pl	déblocages
$




débogage	S.()
_	nom mas sg	débogage
_	nom mas pl	débogages
$
débogueur	S.()
_	nom mas sg	débogueur
_	nom mas pl	débogueurs
................................................................................
_	adj mas sg	décisif
_	adj mas pl	décisifs
$
décisoire	S.()
_	adj epi sg	décisoire
_	adj epi pl	décisoires
$




déclamation	S.()
_	nom fem sg	déclamation
_	nom fem pl	déclamations
$
déclamatoire	S.()
_	adj epi sg	déclamatoire
_	adj epi pl	déclamatoires
................................................................................
_	nom fem sg	dédifférenciation
_	nom fem pl	dédifférenciations
$
dédit	S.()
_	nom mas sg	dédit
_	nom mas pl	dédits
$




dédommagement	S.()
_	nom mas sg	dédommagement
_	nom mas pl	dédommagements
$
dédorage	S.()
_	nom mas sg	dédorage
_	nom mas pl	dédorages
................................................................................
_	nom mas sg	démariage
_	nom mas pl	démariages
$
démarquage	S.()
_	nom mas sg	démarquage
_	nom mas pl	démarquages
$




démarqueuse	F.()
_	nom fem sg	démarqueuse
_	nom fem pl	démarqueuses
_	nom mas sg	démarqueur
_	nom mas pl	démarqueurs
$
démarrage	S.()
................................................................................
_	nom mas sg	dépolissage
_	nom mas pl	dépolissages
$
dépolitisation	S.()
_	nom fem sg	dépolitisation
_	nom fem pl	dépolitisations
$






dépollution	S.()
_	nom fem sg	dépollution
_	nom fem pl	dépollutions
$
dépolymérisation	S.()
_	nom fem sg	dépolymérisation
_	nom fem pl	dépolymérisations
................................................................................
_	nom mas sg	déprimé
_	nom mas pl	déprimés
$
déprimogène	S.()
_	adj epi sg	déprimogène
_	adj epi pl	déprimogènes
$




déprogrammation	S.()
_	nom fem sg	déprogrammation
_	nom fem pl	déprogrammations
$
déprolétarisation	S.()
_	nom fem sg	déprolétarisation
_	nom fem pl	déprolétarisations
................................................................................
_	nom epi sg	dogmatiste
_	nom epi pl	dogmatistes
$
dogme	S.()
_	nom mas sg	dogme
_	nom mas pl	dogmes
$






dogue	S.()
_	nom mas sg	dogue
_	nom mas pl	dogues
$
doigt	S.()
_	nom mas sg	doigt
_	nom mas pl	doigts
................................................................................
_	nom epi sg	droguiste
_	nom epi pl	droguistes
$
droïde	S.()
_	nom mas sg	droïde
_	nom mas pl	droïdes
$
droit-de-l'hommisme	S.()
_	nom mas sg	droit-de-l'hommisme
_	nom mas pl	droit-de-l'hommismes
$
droit-de-l'hommiste	S.()
_	nom adj epi sg	droit-de-l'hommiste
_	nom adj epi pl	droit-de-l'hommistes
$
droite	F.()
_	nom adj fem sg	droite
_	nom adj fem pl	droites
_	nom adj mas sg	droit
_	nom adj mas pl	droits
$
................................................................................
_	nom mas sg	écœurement
_	nom mas pl	écœurements
$
écogeste	S*()
_	nom mas sg	écogeste
_	nom mas pl	écogestes
$




écohabitat	S*()
_	nom mas sg	écohabitat
_	nom mas pl	écohabitats
$
écoinçon	S*()
_	nom mas sg	écoinçon
_	nom mas pl	écoinçons
................................................................................
_	nom fem sg	électroencéphalographie
_	nom fem pl	électroencéphalographies
$
électro-encéphalographie	S*()
_	nom fem sg	électro-encéphalographie
_	nom fem pl	électro-encéphalographies
$








électrofaible	S*()
_	adj epi sg	électrofaible
_	adj epi pl	électrofaibles
$
électro-faible	S*()
_	adj epi sg	électro-faible
_	adj epi pl	électro-faibles
................................................................................
_	nom mas sg	étendoir
_	nom mas pl	étendoirs
$
étendue	S*()
_	nom fem sg	étendue
_	nom fem pl	étendues
$




éternelle	F*()
_	adj fem sg	éternelle
_	adj fem pl	éternelles
_	adj mas sg	éternel
_	adj mas pl	éternels
$
éternité	S*()
................................................................................
_	nom mas sg	exondement
_	nom mas pl	exondements
$
exonération	S*()
_	nom fem sg	exonération
_	nom fem pl	exonérations
$




exonyme	S*()
_	nom mas sg	exonyme
_	nom mas pl	exonymes
$
exonymie	S*()
_	nom fem sg	exonymie
_	nom fem pl	exonymies
................................................................................
_	nom fem sg	extrémité
_	nom fem pl	extrémités
$
extrémophile	S*()
_	nom adj epi sg	extrémophile
_	nom adj epi pl	extrémophiles
$
extremum	S*()
_	nom mas sg	extremum
_	nom mas pl	extremums

$
extrémum	S*()
_	nom mas sg	extrémum
_	nom mas pl	extrémums
$
extrinsécisme	S*()
_	nom mas sg	extrinsécisme
................................................................................
_	nom fem pl	finances
$
financement	S.()
_	nom mas sg	financement
_	nom mas pl	financements
$
financeuse	F.()
_	nom fem sg	financeuse
_	nom fem pl	financeuses
_	nom mas sg	financeur
_	nom mas pl	financeurs
$
financiarisation	S.()
_	nom fem sg	financiarisation
_	nom fem pl	financiarisations
$
financiarisme	S.()
_	nom mas sg	financiarisme
................................................................................
_	nom fem sg	gayolle
_	nom fem pl	gayolles
$
gazage	S.()
_	nom mas sg	gazage
_	nom mas pl	gazages
$






gaze	S.()
_	nom fem sg	gaze
_	nom fem pl	gazes
$
gazée	F.()
_	nom fem sg	gazée
_	nom fem pl	gazées
................................................................................
_	nom fem sg	gougnote
_	nom fem pl	gougnotes
$
gougnotte	S.()
_	nom fem sg	gougnotte
_	nom fem pl	gougnottes
$




gouine	S.()
_	nom fem sg	gouine
_	nom fem pl	gouines
$
goujat	S.()
_	nom mas sg	goujat
_	nom mas pl	goujats
................................................................................
_	nom mas sg	gratteur
_	nom mas pl	gratteurs
$
grattoir	S.()
_	nom mas sg	grattoir
_	nom mas pl	grattoirs
$




grattouille	S.()
_	nom fem sg	grattouille
_	nom fem pl	grattouilles
$
gratture	S.()
_	nom fem sg	gratture
_	nom fem pl	grattures
................................................................................
_	adj epi sg	hégémonique
_	adj epi pl	hégémoniques
$
hégémonisme	S*()
_	nom mas sg	hégémonisme
_	nom mas pl	hégémonismes
$




hégire	S*()
_	nom fem sg	hégire
_	nom fem pl	hégires
$
hégirienne	F*()
_	adj fem sg	hégirienne
_	adj fem pl	hégiriennes
................................................................................
_	nom mas sg	hihan
_	nom mas pl	hihans
$
hijab	S.()
_	nom mas sg	hijab
_	nom mas pl	hijabs
$




hilaire	S.()
_	adj epi sg	hilaire
_	adj epi pl	hilaires
$
hilarante	F*()
_	adj fem sg	hilarante
_	adj fem pl	hilarantes
................................................................................
_	adj epi sg	hyperchrome
_	adj epi pl	hyperchromes
$
hyperchromie	S*()
_	nom fem sg	hyperchromie
_	nom fem pl	hyperchromies
$




hypercomplexe	S*()
_	adj epi sg	hypercomplexe
_	adj epi pl	hypercomplexes
$
hyperconformisme	S*()
_	nom mas sg	hyperconformisme
_	nom mas pl	hyperconformismes
................................................................................
$
hypercontinentale	W*()
_	adj fem sg	hypercontinentale
_	adj fem pl	hypercontinentales
_	adj mas sg	hypercontinental
_	adj mas pl	hypercontinentaux
$




hypercorrecte	F*()
_	adj fem sg	hypercorrecte
_	adj fem pl	hypercorrectes
_	adj mas sg	hypercorrect
_	adj mas pl	hypercorrects
$
hypercorrection	S*()
................................................................................
_	adj epi sg	hyperonymique
_	adj epi pl	hyperonymiques
$
hyperostose	S*()
_	nom fem sg	hyperostose
_	nom fem pl	hyperostoses
$




hyperparasite	S*()
_	nom mas sg	hyperparasite
_	nom mas pl	hyperparasites
$
hyperparathyroïdie	S*()
_	nom fem sg	hyperparathyroïdie
_	nom fem pl	hyperparathyroïdies
................................................................................
_	nom fem sg	hyperplasie
_	nom fem pl	hyperplasies
$
hyperplasique	S*()
_	adj epi sg	hyperplasique
_	adj epi pl	hyperplasiques
$




hyperprolactinémie	S*()
_	nom fem sg	hyperprolactinémie
_	nom fem pl	hyperprolactinémies
$
hyperpuissance	S*()
_	nom fem sg	hyperpuissance
_	nom fem pl	hyperpuissances
................................................................................
_	adj mas sg	impératif
_	adj mas pl	impératifs
$
impératrice	S*()
_	nom fem sg	impératrice
_	nom fem pl	impératrices
$




imperceptibilité	S*()
_	nom fem sg	imperceptibilité
_	nom fem pl	imperceptibilités
$
imperceptible	S*()
_	adj epi sg	imperceptible
_	adj epi pl	imperceptibles
................................................................................
_	nom fem sg	imprescriptibilité
_	nom fem pl	imprescriptibilités
$
imprescriptible	S*()
_	adj epi sg	imprescriptible
_	adj epi pl	imprescriptibles
$




impression	S*()
_	nom fem sg	impression
_	nom fem pl	impressions
$
impressionnabilité	S*()
_	nom fem sg	impressionnabilité
_	nom fem pl	impressionnabilités
................................................................................
_	adj epi sg	increvable
_	adj epi pl	increvables
$
incriminable	S*()
_	adj epi sg	incriminable
_	adj epi pl	incriminables
$






incrimination	S*()
_	nom fem sg	incrimination
_	nom fem pl	incriminations
$
incristallisable	S*()
_	adj epi sg	incristallisable
_	adj epi pl	incristallisables
................................................................................
_	nom adj mas sg	jamaïquain
_	nom adj mas pl	jamaïquains
$
jambage	S.()
_	nom mas sg	jambage
_	nom mas pl	jambages
$




jambart	S.()
_	nom mas sg	jambart
_	nom mas pl	jambarts
$
jambe	S.()
_	nom fem sg	jambe
_	nom fem pl	jambes
................................................................................
_	nom mas sg	jéjuno-iléon
_	nom mas pl	jéjuno-iléons
$
jéjunum	S.()
_	nom mas sg	jéjunum
_	nom mas pl	jéjunums
$
je-m'en-fichisme	S.()
_	nom mas sg	je-m'en-fichisme
_	nom mas pl	je-m'en-fichismes
$
je-m'en-fichiste	S.()
_	nom adj epi sg	je-m'en-fichiste
_	nom adj epi pl	je-m'en-fichistes
$
je-m'en-foutisme	S.()
_	nom mas sg	je-m'en-foutisme
_	nom mas pl	je-m'en-foutismes
$
je-m'en-foutiste	S.()
_	nom adj epi sg	je-m'en-foutiste
_	nom adj epi pl	je-m'en-foutistes
$
jennérienne	F.()
_	adj fem sg	jennérienne
_	adj fem pl	jennériennes
_	adj mas sg	jennérien
_	adj mas pl	jennériens
$
................................................................................
_	nom mas sg	jusnaturalisme
_	nom mas pl	jusnaturalismes
$
jusnaturaliste	S.()
_	nom adj epi sg	jusnaturaliste
_	nom adj epi pl	jusnaturalistes
$
jusqu'au-boutisme	S.()
_	nom mas sg	jusqu'au-boutisme
_	nom mas pl	jusqu'au-boutismes
$
jusqu'au-boutiste	S.()
_	nom epi sg	jusqu'au-boutiste
_	nom epi pl	jusqu'au-boutistes
$
jusquiame	S.()
_	nom fem sg	jusquiame
_	nom fem pl	jusquiames
$








jussiée	S.()
_	nom fem sg	jussiée
_	nom fem pl	jussiées
$
jussion	S.()
_	nom fem sg	jussion
_	nom fem pl	jussions
................................................................................
_	adj epi sg	magnétoélectrique
_	adj epi pl	magnétoélectriques
$
magnéto-électrique	S.()
_	adj epi sg	magnéto-électrique
_	adj epi pl	magnéto-électriques
$




magnétogaine	S.()
_	nom fem sg	magnétogaine
_	nom fem pl	magnétogaines
$
magnétohydrodynamique	S.()
_	adj epi sg	magnétohydrodynamique
_	adj epi pl	magnétohydrodynamiques
................................................................................
_	nom mas sg	mammouth
_	nom mas pl	mammouths
$
mammy	S.()
_	nom fem sg	mammy
_	nom fem pl	mammys
$
mam'selle	S.()
_	nom fem sg	mam'selle
_	nom fem pl	mam'selles
$
mamy	S.()
_	nom fem sg	mamy
_	nom fem pl	mamys
$




mam'zelle	S.()
_	nom fem sg	mam'zelle
_	nom fem pl	mam'zelles
$
man	S.()
_	nom mas sg	man
_	nom mas pl	mans
$
mana	S.()
_	nom mas sg	mana
................................................................................
$
marchandeuse	F.()
_	nom fem sg	marchandeuse
_	nom fem pl	marchandeuses
_	nom mas sg	marchandeur
_	nom mas pl	marchandeurs
$




marchandisage	S.()
_	nom mas sg	marchandisage
_	nom mas pl	marchandisages
$
marchandisation	S.()
_	nom fem sg	marchandisation
_	nom fem pl	marchandisations
................................................................................
_	nom mas sg	méaculpa
_	nom mas pl	méaculpas
$
méandre	S.()
_	nom mas sg	méandre
_	nom mas pl	méandres
$





méandriforme	S.()
_	adj epi sg	méandriforme
_	adj epi pl	méandriformes
$
méandrine	S.()
_	nom fem sg	méandrine
_	nom fem pl	méandrines
................................................................................
_	nom fem sg	mésalliance
_	nom fem pl	mésalliances
$
mésange	S.()
_	nom fem sg	mésange
_	nom fem pl	mésanges
$




mésangette	S.()
_	nom fem sg	mésangette
_	nom fem pl	mésangettes
$
mésappariement	S.()
_	nom mas sg	mésappariement
_	nom mas pl	mésappariements
................................................................................
_	adj mas sg	mesmérien
_	adj mas pl	mesmériens
$
mesmérisme	S.()
_	nom mas sg	mesmérisme
_	nom mas pl	mesmérismes
$






mésoblaste	S.()
_	nom mas sg	mésoblaste
_	nom mas pl	mésoblastes
$
mésoblastique	S.()
_	adj epi sg	mésoblastique
_	adj epi pl	mésoblastiques
................................................................................
_	adj mas sg	microlocalisé
_	adj mas pl	microlocalisés
$
micrologiciel	S.()
_	nom mas sg	micrologiciel
_	nom mas pl	micrologiciels
$




micromanipulateur	S.()
_	nom mas sg	micromanipulateur
_	nom mas pl	micromanipulateurs
$
micromanipulation	S.()
_	nom fem sg	micromanipulation
_	nom fem pl	micromanipulations
$




micromélange	S.()
_	nom mas sg	micromélange
_	nom mas pl	micromélanges
$
micromélangeage	S.()
_	nom mas sg	micromélangeage
_	nom mas pl	micromélangeages
................................................................................
_	nom mas sg	monocamérisme
_	nom mas pl	monocamérismes
$
monocarboxylique	S.()
_	adj epi sg	monocarboxylique
_	adj epi pl	monocarboxyliques
$




monocaténaire	S.()
_	adj epi sg	monocaténaire
_	adj epi pl	monocaténaires
$
monocellulaire	S.()
_	adj epi sg	monocellulaire
_	adj epi pl	monocellulaires
................................................................................
_	adj epi sg	néphrotique
_	adj epi pl	néphrotiques
$
néphrotoxique	S.()
_	adj epi sg	néphrotoxique
_	adj epi pl	néphrotoxiques
$




népotisme	S.()
_	nom mas sg	népotisme
_	nom mas pl	népotismes
$
neptunium	S.()
_	nom mas sg	neptunium
_	nom mas pl	neptuniums
................................................................................
_	nom epi sg	neuroanatomiste
_	nom epi pl	neuroanatomistes
$
neuro-anatomiste	S.()
_	nom epi sg	neuro-anatomiste
_	nom epi pl	neuro-anatomistes
$








neurobiochimie	S.()
_	nom fem sg	neurobiochimie
_	nom fem pl	neurobiochimies
$
neurobiochimique	S.()
_	adj epi sg	neurobiochimique
_	adj epi pl	neurobiochimiques
................................................................................
_	nom fem sg	orchidacée
_	nom fem pl	orchidacées
$
orchidée	S*()
_	nom fem sg	orchidée
_	nom fem pl	orchidées
$




orchiépididymite	S*()
_	nom fem sg	orchiépididymite
_	nom fem pl	orchiépididymites
$
orchi-épididymite	S*()
_	nom fem sg	orchi-épididymite
_	nom fem pl	orchi-épididymites
................................................................................
_	nom fem sg	pala
_	nom fem pl	palas
$
palabre	S.()
_	nom epi sg	palabre
_	nom epi pl	palabres
$






palace	S.()
_	nom mas sg	palace
_	nom mas pl	palaces
$
paladin	S.()
_	nom mas sg	paladin
_	nom mas pl	paladins
................................................................................
_	nom fem sg	parisette
_	nom fem pl	parisettes
$
parisianisme	S.()
_	nom mas sg	parisianisme
_	nom mas pl	parisianismes
$




parisienne	F.()
_	nom adj fem sg	parisienne
_	nom adj fem pl	parisiennes
_	nom adj mas sg	parisien
_	nom adj mas pl	parisiens
$
parisyllabique	S.()
................................................................................
$
pénale	W.()
_	adj fem sg	pénale
_	adj fem pl	pénales
_	adj mas sg	pénal
_	adj mas pl	pénaux
$




pénalisante	F.()
_	adj fem sg	pénalisante
_	adj fem pl	pénalisantes
_	adj mas sg	pénalisant
_	adj mas pl	pénalisants
$
pénalisation	S.()
................................................................................
_	nom mas sg	péramèle
_	nom mas pl	péramèles
$
perborate	S.()
_	nom mas sg	perborate
_	nom mas pl	perborates
$




perçage	S.()
_	nom mas sg	perçage
_	nom mas pl	perçages
$
percale	S.()
_	nom epi sg	percale
_	nom epi pl	percales
................................................................................
_	nom fem pl	pétéchies
$
pétersbourgeoise	F.()
_	nom adj fem sg	pétersbourgeoise
_	nom adj fem pl	pétersbourgeoises
_	nom adj mas inv	pétersbourgeois
$
pète-sec	S.()
_	nom adj epi sg	pète-sec
_	nom adj epi pl	pète-secs
$
péteuse	F.()
_	nom fem sg	péteuse
_	nom fem pl	péteuses
_	nom mas sg	péteur
_	nom mas pl	péteurs
$
péteuse	W.()
................................................................................
_	nom mas pl	piémonts
$
piémontaise	F.()
_	nom adj fem sg	piémontaise
_	nom adj fem pl	piémontaises
_	nom adj mas inv	piémontais
$




piercing	S.()
_	nom mas sg	piercing
_	nom mas pl	piercings
$
piéride	S.()
_	nom fem sg	piéride
_	nom fem pl	piérides
................................................................................
$
politico-financière	F.()
_	adj fem sg	politico-financière
_	adj fem pl	politico-financières
_	adj mas sg	politico-financier
_	adj mas pl	politico-financiers
$




politicologue	S.()
_	nom epi sg	politicologue
_	nom epi pl	politicologues
$
politico-médiatique	S.()
_	adj epi sg	politico-médiatique
_	adj epi pl	politico-médiatiques
................................................................................
$
présentielle	F.()
_	nom adj fem sg	présentielle
_	nom adj fem pl	présentielles
_	nom adj mas sg	présentiel
_	nom adj mas pl	présentiels
$




présentoir	S.()
_	nom mas sg	présentoir
_	nom mas pl	présentoirs
$
présérie	S.()
_	nom fem sg	présérie
_	nom fem pl	préséries
................................................................................
_	nom fem sg	présidentialisation
_	nom fem pl	présidentialisations
$
présidentialisme	S.()
_	nom mas sg	présidentialisme
_	nom mas pl	présidentialismes
$




présidentielle	F.()
_	adj fem sg	présidentielle
_	adj fem pl	présidentielles
_	adj mas sg	présidentiel
_	adj mas pl	présidentiels
$
présidial	X.()
................................................................................
_	nom adj fem pl	présomptueuses
_	nom adj mas inv	présomptueux
$
présonorisation	S.()
_	nom fem sg	présonorisation
_	nom fem pl	présonorisations
$
presqu'ile	S.()
_	nom fem sg	presqu'ile
_	nom fem pl	presqu'iles
$
presqu'île	S.()
_	nom fem sg	presqu'île
_	nom fem pl	presqu'îles
$
pressabilité	S.()
_	nom fem sg	pressabilité
_	nom fem pl	pressabilités
$
pressage	S.()
_	nom mas sg	pressage
................................................................................
_	adj mas sg	prudentiel
_	adj mas pl	prudentiels
$
pruderie	S.()
_	nom fem sg	pruderie
_	nom fem pl	pruderies
$
prud'homale	W.()
_	adj fem sg	prud'homale
_	adj fem pl	prud'homales
_	adj mas sg	prud'homal
_	adj mas pl	prud'homaux
$
prud'homie	S.()
_	nom fem sg	prud'homie
_	nom fem pl	prud'homies
$
prudhommale	W.()
_	adj fem sg	prudhommale
_	adj fem pl	prudhommales
_	adj mas sg	prudhommal
_	adj mas pl	prudhommaux
$
prudhomme	S.()
_	nom mas sg	prudhomme
_	nom mas pl	prudhommes
$
prud'homme	S.()
_	nom mas sg	prud'homme
_	nom mas pl	prud'hommes
$
prudhommerie	S.()
_	nom fem sg	prudhommerie
_	nom fem pl	prudhommeries
$
prudhommesque	S.()
_	adj epi sg	prudhommesque
_	adj epi pl	prudhommesques
$
prudhommie	S.()
_	nom fem sg	prudhommie
_	nom fem pl	prudhommies
$














pruine	S.()
_	nom fem sg	pruine
_	nom fem pl	pruines
$
prune	S.()
_	nom epi sg	prune
_	nom epi pl	prunes
................................................................................
_	adj mas sg	ptérygoïdien
_	adj mas pl	ptérygoïdiens
$
ptérygote	S.()
_	nom mas sg	ptérygote
_	nom mas pl	ptérygotes
$
p'tite	F.()
_	nom adj fem sg	p'tite
_	nom adj fem pl	p'tites
_	nom adj mas sg	p'tit
_	nom adj mas pl	p'tits
$
ptolémaïque	S.()
_	adj epi sg	ptolémaïque
_	adj epi pl	ptolémaïques
$
ptoléméenne	F.()
_	adj fem sg	ptoléméenne
_	adj fem pl	ptoléméennes
................................................................................
_	nom fem sg	pyélonéphrite
_	nom fem pl	pyélonéphrites
$
pygargue	S.()
_	nom mas sg	pygargue
_	nom mas pl	pygargues
$




pygmée	S.()
_	nom adj epi sg	pygmée
_	nom adj epi pl	pygmées
$
pygméenne	F.()
_	adj fem sg	pygméenne
_	adj fem pl	pygméennes
................................................................................
_	nom fem sg	pyurie
_	nom fem pl	pyuries
$
pyxide	S.()
_	nom fem sg	pyxide
_	nom fem pl	pyxides
$






qanat	S.()
_	nom mas sg	qanat
_	nom mas pl	qanats
$
qat	S.()
_	nom mas sg	qat
_	nom mas pl	qats
................................................................................
_	nom fem sg	ratification
_	nom fem pl	ratifications
$
ratinage	S.()
_	nom mas sg	ratinage
_	nom mas pl	ratinages
$




rating	S.()
_	nom mas sg	rating
_	nom mas pl	ratings
$
ratio	S.()
_	nom mas sg	ratio
_	nom mas pl	ratios
................................................................................
_	nom mas sg	recéleur
_	nom mas pl	recéleurs
$
récence	S.()
_	nom fem sg	récence
_	nom fem pl	récences
$




recensement	S.()
_	nom mas sg	recensement
_	nom mas pl	recensements
$
recenseuse	F.()
_	nom fem sg	recenseuse
_	nom fem pl	recenseuses
................................................................................
$
recycleuse	F.()
_	nom adj fem sg	recycleuse
_	nom adj fem pl	recycleuses
_	nom adj mas sg	recycleur
_	nom adj mas pl	recycleurs
$




rédaction	S.()
_	nom fem sg	rédaction
_	nom fem pl	rédactions
$
rédactionnel	S.()
_	nom mas sg	rédactionnel
_	nom mas pl	rédactionnels
................................................................................
rédemptrice	F.()
_	nom adj fem sg	rédemptrice
_	nom adj fem pl	rédemptrices
_	nom adj mas sg	rédempteur
_	nom adj mas pl	rédempteurs
$
redénomination	S.()
_	nom mas sg	redénomination
_	nom mas pl	redénominations
$
redent	S.()
_	nom mas sg	redent
_	nom mas pl	redents
$
redentée	F.()
_	adj fem sg	redentée
................................................................................
$
remblayeuse	F.()
_	nom fem sg	remblayeuse
_	nom fem pl	remblayeuses
_	nom mas sg	remblayeur
_	nom mas pl	remblayeurs
$




remboitage	S.()
_	nom mas sg	remboitage
_	nom mas pl	remboitages
$
remboîtage	S.()
_	nom mas sg	remboîtage
_	nom mas pl	remboîtages
................................................................................
$
ressortissante	F.()
_	nom adj fem sg	ressortissante
_	nom adj fem pl	ressortissantes
_	nom adj mas sg	ressortissant
_	nom adj mas pl	ressortissants
$




ressource	S.()
_	nom fem sg	ressource
_	nom fem pl	ressources
$
ressourcement	S.()
_	nom mas sg	ressourcement
_	nom mas pl	ressourcements
................................................................................
$
russo-turque	F.()
_	nom adj fem sg	russo-turque
_	nom adj fem pl	russo-turques
_	nom adj mas sg	russo-turc
_	nom adj mas pl	russo-turcs
$






russule	S.()
_	nom fem sg	russule
_	nom fem pl	russules
$
rustaude	F.()
_	nom adj fem sg	rustaude
_	nom adj fem pl	rustaudes
................................................................................
_	adj epi sg	sadique
_	adj epi pl	sadiques
$
sadisme	S.()
_	nom mas sg	sadisme
_	nom mas pl	sadismes
$




sadomasochisme	S.()
_	nom mas sg	sadomasochisme
_	nom mas pl	sadomasochismes
$
sado-masochisme	S.()
_	nom mas sg	sado-masochisme
_	nom mas pl	sado-masochismes
................................................................................
_	nom mas sg	storyboard
_	nom mas pl	storyboards
$
story-board	S.()
_	nom mas sg	story-board
_	nom mas pl	story-boards
$




stot	S.()
_	nom mas sg	stot
_	nom mas pl	stots
$
stoupa	S.()
_	nom mas sg	stoupa
_	nom mas pl	stoupas
................................................................................
_	adj mas sg	surhumain
_	adj mas pl	surhumains
$
surhumanité	S.()
_	nom fem sg	surhumanité
_	nom fem pl	surhumanités
$




suricate	S.()
_	nom mas sg	suricate
_	nom mas pl	suricates
$
surie	F.()
_	adj fem sg	surie
_	adj fem pl	suries
................................................................................
_	nom fem sg	surjeteuse
_	nom fem pl	surjeteuses
$
surjeu	X.()
_	nom mas sg	surjeu
_	nom mas pl	surjeux
$




surlargeur	S.()
_	nom fem sg	surlargeur
_	nom fem pl	surlargeurs
$
surlendemain	S.()
_	nom mas sg	surlendemain
_	nom mas pl	surlendemains
................................................................................
$
surprenante	F.()
_	adj fem sg	surprenante
_	adj fem pl	surprenantes
_	adj mas sg	surprenant
_	adj mas pl	surprenants
$




surpresseur	S.()
_	nom mas sg	surpresseur
_	nom mas pl	surpresseurs
$
surpression	S.()
_	nom fem sg	surpression
_	nom fem pl	surpressions
................................................................................
_	nom mas sg	tâteur
_	nom mas pl	tâteurs
$
tâte-vin	S.()
_	nom mas sg	tâte-vin
_	nom mas pl	tâte-vins
$




tatillonnage	S.()
_	nom mas sg	tatillonnage
_	nom mas pl	tatillonnages
$
tatillonne	F.()
_	nom adj fem sg	tatillonne
_	nom adj fem pl	tatillonnes
................................................................................
_	nom fem sg	technocratisation
_	nom fem pl	technocratisations
$
technocratisme	S.()
_	nom mas sg	technocratisme
_	nom mas pl	technocratismes
$












technoéconomique	S.()
_	adj epi sg	technoéconomique
_	adj epi pl	technoéconomiques
$
techno-économique	S.()
_	adj epi sg	techno-économique
_	adj epi pl	techno-économiques
................................................................................
_	adj epi sg	télémétrique
_	adj epi pl	télémétriques
$
télencéphale	S.()
_	nom mas sg	télencéphale
_	nom mas pl	télencéphales
$




téléobjectif	S.()
_	nom mas sg	téléobjectif
_	nom mas pl	téléobjectifs
$
téléologie	S.()
_	nom fem sg	téléologie
_	nom fem pl	téléologies
................................................................................
_	nom adj fem pl	ténébreuses
_	nom adj mas inv	ténébreux
$
ténébrion	S.()
_	nom mas sg	ténébrion
_	nom mas pl	ténébrions
$




tènement	S.()
_	nom mas sg	tènement
_	nom mas pl	tènements
$
ténesme	S.()
_	nom mas sg	ténesme
_	nom mas pl	ténesmes
................................................................................
_	nom mas sg	tépidarium
_	nom mas pl	tépidariums
$
tépographie	S.()
_	nom fem sg	tépographie
_	nom fem pl	tépographies
$




tequila	S.()
_	nom fem sg	tequila
_	nom fem pl	tequilas
$
téquila	S.()
_	nom fem sg	téquila
_	nom fem pl	téquilas
................................................................................
$
transhumante	F.()
_	nom adj fem sg	transhumante
_	nom adj fem pl	transhumantes
_	nom adj mas sg	transhumant
_	nom adj mas pl	transhumants
$




transidentité	S.()
_	nom fem sg	transidentité
_	nom fem pl	transidentités
$
transigeance	S.()
_	nom fem sg	transigeance
_	nom fem pl	transigeances
................................................................................
_	nom mas sg	triton
_	nom mas pl	tritons
$
triturable	S.()
_	adj epi sg	triturable
_	adj epi pl	triturables
$




triturateur	S.()
_	nom mas sg	triturateur
_	nom mas pl	triturateurs
$
trituration	S.()
_	nom fem sg	trituration
_	nom fem pl	triturations
................................................................................
_	nom mas sg	troll
_	nom mas pl	trolls
$
trolle	S.()
_	nom fem sg	trolle
_	nom fem pl	trolles
$




trolley	S.()
_	nom mas sg	trolley
_	nom mas pl	trolleys
$
trombe	S.()
_	nom fem sg	trombe
_	nom fem pl	trombes
................................................................................
_	nom adj epi sg	ultracolonialiste
_	nom adj epi pl	ultracolonialistes
$
ultra-colonialiste	S*()
_	nom adj epi sg	ultra-colonialiste
_	nom adj epi pl	ultra-colonialistes
$






ultraconfidentielle	F*()
_	adj fem sg	ultraconfidentielle
_	adj fem pl	ultraconfidentielles
_	adj mas sg	ultraconfidentiel
_	adj mas pl	ultraconfidentiels
$
ultra-confidentielle	F*()
................................................................................
$
verticale	W.()
_	nom adj fem sg	verticale
_	nom adj fem pl	verticales
_	nom adj mas sg	vertical
_	nom adj mas pl	verticaux
$




verticalisation	S.()
_	nom fem sg	verticalisation
_	nom fem pl	verticalisations
$
verticalité	S.()
_	nom fem sg	verticalité
_	nom fem pl	verticalités
................................................................................
_	adj mas sg	victimisant
_	adj mas pl	victimisants
$
victimisation	S.()
_	nom fem sg	victimisation
_	nom fem pl	victimisations
$




victimologie	S.()
_	nom fem sg	victimologie
_	nom fem pl	victimologies
$
victimologue	S.()
_	nom epi sg	victimologue
_	nom epi pl	victimologues
................................................................................
_	nom fem sg	vidéoprojection
_	nom fem pl	vidéoprojections
$
vidéoprotection	S.()
_	nom fem sg	vidéoprotection
_	nom fem pl	vidéoprotections
$




vide-ordure	S.()
_	nom mas sg	vide-ordure
_	nom mas pl	vide-ordures
$
vidéosphère	S.()
_	nom fem sg	vidéosphère
_	nom fem pl	vidéosphères
................................................................................
_	adj epi sg	vierge
_	adj epi pl	vierges
$
vierge	S.()
_	nom fem sg	vierge
_	nom fem pl	vierges
$




vietnamienne	F.()
_	nom adj fem sg	vietnamienne
_	nom adj fem pl	vietnamiennes
_	nom adj mas sg	vietnamien
_	nom adj mas pl	vietnamiens
$
vigésimale	W.()
................................................................................
_	nom mas sg	voyer
_	nom mas pl	voyers
$
voyeurisme	S.()
_	nom mas sg	voyeurisme
_	nom mas pl	voyeurismes
$




voyeuse	F.()
_	nom adj fem sg	voyeuse
_	nom adj fem pl	voyeuses
_	nom adj mas sg	voyeur
_	nom adj mas pl	voyeurs
$
voyou	S.()







>
>
>
>







 







>
>
>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







<
<
<
<
<
<






<
<
<
<










>
>
>
>
>
>
>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







<
<
<
<







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>
>
>







 







>
>
>
>







 







>
>
>
>
>
>







 







|
|
|

|
|
|







 







>
>
>
>







 







>
>
>
>
>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







|


>







 







|
|
|
|







 







>
>
>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>
>
>







 







>
>
>
>







 







|
|
|

|
|
|

|
|
|

|
|
|







 







<
<
<
<
<
<
<
<




>
>
>
>
>
>
>
>







 







>
>
>
>







 







<
<
<
<




>
>
>
>
|
|
|







 







>
>
>
>







 







>
>
>
>
>







 







>
>
>
>







 







>
>
>
>
>
>







 







>
>
>
>








>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>
>
>
>
>







 







>
>
>
>







 







>
>
>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







<
<
<
<







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







|
|
|

|
|
|







 







<
<
<
<
<
<
<
<
<
<










<
<
<
<












>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<
<
<
<
<
<







 







>
>
>
>







 







>
>
>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







|
|







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







 







>
>
>
>







342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
....
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
....
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
....
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
.....
14291
14292
14293
14294
14295
14296
14297
14298
14299
14300
14301
14302
14303
14304
14305
14306
14307
14308
.....
16408
16409
16410
16411
16412
16413
16414
16415
16416
16417
16418
16419
16420
16421
16422
16423
16424
16425
.....
20997
20998
20999
21000
21001
21002
21003
21004
21005
21006
21007
21008
21009
21010
21011
21012
21013
21014
.....
21621
21622
21623
21624
21625
21626
21627
21628
21629
21630
21631
21632
21633
21634
21635
21636
21637
21638
.....
21995
21996
21997
21998
21999
22000
22001
22002
22003
22004
22005
22006
22007
22008
22009
22010
22011
22012
.....
22542
22543
22544
22545
22546
22547
22548
22549
22550
22551
22552
22553
22554
22555
22556
22557
22558
22559
.....
22777
22778
22779
22780
22781
22782
22783
22784
22785
22786
22787
22788
22789
22790
22791
22792
22793
22794
.....
23581
23582
23583
23584
23585
23586
23587






23588
23589
23590
23591
23592
23593




23594
23595
23596
23597
23598
23599
23600
23601
23602
23603
23604
23605
23606
23607
23608
23609
23610
23611
23612
23613
23614
23615
23616
23617
23618
23619
23620
.....
27479
27480
27481
27482
27483
27484
27485
27486
27487
27488
27489
27490
27491
27492
27493
27494
27495
27496
.....
30654
30655
30656
30657
30658
30659
30660
30661
30662
30663
30664
30665
30666
30667
30668
30669
30670
30671
.....
32443
32444
32445
32446
32447
32448
32449
32450
32451
32452
32453
32454
32455
32456
32457
32458
32459
32460
.....
33633
33634
33635
33636
33637
33638
33639
33640
33641
33642
33643
33644
33645
33646
33647
33648
33649
33650
.....
34228
34229
34230
34231
34232
34233
34234
34235
34236
34237
34238
34239
34240
34241
34242
34243
34244
34245
.....
34644
34645
34646
34647
34648
34649
34650
34651
34652
34653
34654
34655
34656
34657
34658
34659
34660
34661
.....
36750
36751
36752
36753
36754
36755
36756
36757
36758
36759
36760
36761
36762
36763
36764
36765
36766
36767
.....
44445
44446
44447
44448
44449
44450
44451
44452
44453
44454
44455
44456
44457
44458
44459
44460
44461
44462
.....
45116
45117
45118
45119
45120
45121
45122
45123
45124
45125
45126
45127
45128
45129
45130
45131
45132
45133
.....
47679
47680
47681
47682
47683
47684
47685




47686
47687
47688
47689
47690
47691
47692
.....
47769
47770
47771
47772
47773
47774
47775
47776
47777
47778
47779
47780
47781
47782
47783
47784
47785
47786
.....
55988
55989
55990
55991
55992
55993
55994
55995
55996
55997
55998
55999
56000
56001
56002
56003
56004
56005
.....
58358
58359
58360
58361
58362
58363
58364
58365
58366
58367
58368
58369
58370
58371
58372
58373
58374
58375
58376
58377
.....
58899
58900
58901
58902
58903
58904
58905
58906
58907
58908
58909
58910
58911
58912
58913
58914
58915
58916
.....
64801
64802
64803
64804
64805
64806
64807
64808
64809
64810
64811
64812
64813
64814
64815
64816
64817
64818
.....
65450
65451
65452
65453
65454
65455
65456
65457
65458
65459
65460
65461
65462
65463
65464
65465
65466
65467
.....
66388
66389
66390
66391
66392
66393
66394
66395
66396
66397
66398
66399
66400
66401
66402
66403
66404
66405
.....
67261
67262
67263
67264
67265
67266
67267
67268
67269
67270
67271
67272
67273
67274
67275
67276
67277
67278
.....
68846
68847
68848
68849
68850
68851
68852
68853
68854
68855
68856
68857
68858
68859
68860
68861
68862
68863
.....
70466
70467
70468
70469
70470
70471
70472
70473
70474
70475
70476
70477
70478
70479
70480
70481
70482
70483
70484
70485
.....
70690
70691
70692
70693
70694
70695
70696
70697
70698
70699
70700
70701
70702
70703
70704
70705
70706
70707
.....
77147
77148
77149
77150
77151
77152
77153
77154
77155
77156
77157
77158
77159
77160
77161
77162
77163
77164
77165
77166
.....
78436
78437
78438
78439
78440
78441
78442
78443
78444
78445
78446
78447
78448
78449
78450
78451
78452
78453
78454
78455
78456
.....
80573
80574
80575
80576
80577
80578
80579
80580
80581
80582
80583
80584
80585
80586
80587
80588
80589
80590
.....
82495
82496
82497
82498
82499
82500
82501
82502
82503
82504
82505
82506
82507
82508
82509
82510
82511
82512
82513
82514
82515
82516
.....
91063
91064
91065
91066
91067
91068
91069
91070
91071
91072
91073
91074
91075
91076
91077
91078
91079
91080
.....
93520
93521
93522
93523
93524
93525
93526
93527
93528
93529
93530
93531
93532
93533
93534
93535
93536
93537
.....
94767
94768
94769
94770
94771
94772
94773
94774
94775
94776
94777
94778
94779
94780
94781
94782
94783
94784
.....
98474
98475
98476
98477
98478
98479
98480
98481
98482
98483
98484
98485
98486
98487
98488
98489
98490
98491
......
106092
106093
106094
106095
106096
106097
106098
106099
106100
106101
106102
106103
106104
106105
106106
106107
106108
106109
106110
106111
......
110078
110079
110080
110081
110082
110083
110084
110085
110086
110087
110088
110089
110090
110091
110092
110093
110094
110095
......
111144
111145
111146
111147
111148
111149
111150
111151
111152
111153
111154
111155
111156
111157
111158
111159
111160
111161
......
114872
114873
114874
114875
114876
114877
114878
114879
114880
114881
114882
114883
114884
114885
114886
114887
114888
114889
......
116865
116866
116867
116868
116869
116870
116871
116872
116873
116874
116875
116876
116877
116878
116879
116880
116881
116882
......
120182
120183
120184
120185
120186
120187
120188
120189
120190
120191
120192
120193
120194
120195
120196
120197
120198
120199
......
120206
120207
120208
120209
120210
120211
120212
120213
120214
120215
120216
120217
120218
120219
120220
120221
120222
120223
......
120493
120494
120495
120496
120497
120498
120499
120500
120501
120502
120503
120504
120505
120506
120507
120508
120509
120510
......
120529
120530
120531
120532
120533
120534
120535
120536
120537
120538
120539
120540
120541
120542
120543
120544
120545
120546
......
123303
123304
123305
123306
123307
123308
123309
123310
123311
123312
123313
123314
123315
123316
123317
123318
123319
123320
......
123818
123819
123820
123821
123822
123823
123824
123825
123826
123827
123828
123829
123830
123831
123832
123833
123834
123835
......
125478
125479
125480
125481
125482
125483
125484
125485
125486
125487
125488
125489
125490
125491
125492
125493
125494
125495
125496
125497
......
133732
133733
133734
133735
133736
133737
133738
133739
133740
133741
133742
133743
133744
133745
133746
133747
133748
133749
......
134199
134200
134201
134202
134203
134204
134205
134206
134207
134208
134209
134210
134211
134212
134213
134214
134215
134216
134217
134218
134219
134220
134221
134222
134223
134224
134225
134226
134227
......
135317
135318
135319
135320
135321
135322
135323








135324
135325
135326
135327
135328
135329
135330
135331
135332
135333
135334
135335
135336
135337
135338
135339
135340
135341
135342
......
144753
144754
144755
144756
144757
144758
144759
144760
144761
144762
144763
144764
144765
144766
144767
144768
144769
144770
......
146240
146241
146242
146243
146244
146245
146246




146247
146248
146249
146250
146251
146252
146253
146254
146255
146256
146257
146258
146259
146260
146261
146262
146263
146264
......
147301
147302
147303
147304
147305
147306
147307
147308
147309
147310
147311
147312
147313
147314
147315
147316
147317
147318
......
149218
149219
149220
149221
149222
149223
149224
149225
149226
149227
149228
149229
149230
149231
149232
149233
149234
149235
149236
......
151411
151412
151413
151414
151415
151416
151417
151418
151419
151420
151421
151422
151423
151424
151425
151426
151427
151428
......
151508
151509
151510
151511
151512
151513
151514
151515
151516
151517
151518
151519
151520
151521
151522
151523
151524
151525
151526
151527
......
153331
153332
153333
153334
153335
153336
153337
153338
153339
153340
153341
153342
153343
153344
153345
153346
153347
153348
153349
153350
153351
153352
153353
153354
153355
153356
153357
153358
153359
153360
......
156302
156303
156304
156305
156306
156307
156308
156309
156310
156311
156312
156313
156314
156315
156316
156317
156318
156319
......
163039
163040
163041
163042
163043
163044
163045
163046
163047
163048
163049
163050
163051
163052
163053
163054
163055
163056
......
163245
163246
163247
163248
163249
163250
163251
163252
163253
163254
163255
163256
163257
163258
163259
163260
163261
163262
163263
163264
163265
163266
......
169625
169626
169627
169628
169629
169630
169631
169632
169633
169634
169635
169636
169637
169638
169639
169640
169641
169642
......
172556
172557
172558
172559
172560
172561
172562
172563
172564
172565
172566
172567
172568
172569
172570
172571
172572
172573
172574
172575
......
175381
175382
175383
175384
175385
175386
175387
175388
175389
175390
175391
175392
175393
175394
175395
175396
175397
175398
......
178122
178123
178124
178125
178126
178127
178128
178129
178130
178131
178132
178133
178134
178135
178136
178137
178138
178139
......
178866
178867
178868
178869
178870
178871
178872
178873
178874
178875
178876
178877
178878
178879
178880
178881
178882
178883
......
180701
180702
180703
180704
180705
180706
180707




180708
180709
180710
180711
180712
180713
180714
......
183699
183700
183701
183702
183703
183704
183705
183706
183707
183708
183709
183710
183711
183712
183713
183714
183715
183716
......
187637
187638
187639
187640
187641
187642
187643
187644
187645
187646
187647
187648
187649
187650
187651
187652
187653
187654
......
192672
192673
192674
192675
192676
192677
192678
192679
192680
192681
192682
192683
192684
192685
192686
192687
192688
192689
......
192726
192727
192728
192729
192730
192731
192732
192733
192734
192735
192736
192737
192738
192739
192740
192741
192742
192743
......
192781
192782
192783
192784
192785
192786
192787
192788
192789
192790
192791
192792
192793
192794
192795
192796
192797
192798
192799
192800
192801
......
195959
195960
195961
195962
195963
195964
195965










195966
195967
195968
195969
195970
195971
195972
195973
195974
195975




195976
195977
195978
195979
195980
195981
195982
195983
195984
195985
195986
195987
195988
195989
195990
195991
195992
195993
195994
195995
195996
195997
195998
195999
196000
196001
196002
196003
196004
196005
196006
196007
196008
......
196902
196903
196904
196905
196906
196907
196908






196909
196910
196911
196912
196913
196914
196915
......
197824
197825
197826
197827
197828
197829
197830
197831
197832
197833
197834
197835
197836
197837
197838
197839
197840
197841
......
198294
198295
198296
198297
198298
198299
198300
198301
198302
198303
198304
198305
198306
198307
198308
198309
198310
198311
198312
198313
......
202030
202031
202032
202033
202034
202035
202036
202037
202038
202039
202040
202041
202042
202043
202044
202045
202046
202047
......
202879
202880
202881
202882
202883
202884
202885
202886
202887
202888
202889
202890
202891
202892
202893
202894
202895
202896
......
203929
203930
203931
203932
203933
203934
203935
203936
203937
203938
203939
203940
203941
203942
203943
203944
203945
203946
......
203996
203997
203998
203999
204000
204001
204002
204003
204004
204005
204006
204007
204008
204009
204010
204011
......
205780
205781
205782
205783
205784
205785
205786
205787
205788
205789
205790
205791
205792
205793
205794
205795
205796
205797
......
207797
207798
207799
207800
207801
207802
207803
207804
207805
207806
207807
207808
207809
207810
207811
207812
207813
207814
......
212554
212555
212556
212557
212558
212559
212560
212561
212562
212563
212564
212565
212566
212567
212568
212569
212570
212571
212572
212573
......
213219
213220
213221
213222
213223
213224
213225
213226
213227
213228
213229
213230
213231
213232
213233
213234
213235
213236
......
227369
227370
227371
227372
227373
227374
227375
227376
227377
227378
227379
227380
227381
227382
227383
227384
227385
227386
......
230653
230654
230655
230656
230657
230658
230659
230660
230661
230662
230663
230664
230665
230666
230667
230668
230669
230670
......
230770
230771
230772
230773
230774
230775
230776
230777
230778
230779
230780
230781
230782
230783
230784
230785
230786
230787
......
231006
231007
231008
231009
231010
231011
231012
231013
231014
231015
231016
231017
231018
231019
231020
231021
231022
231023
......
234104
234105
234106
234107
234108
234109
234110
234111
234112
234113
234114
234115
234116
234117
234118
234119
234120
234121
......
234626
234627
234628
234629
234630
234631
234632
234633
234634
234635
234636
234637
234638
234639
234640
234641
234642
234643
234644
234645
234646
234647
234648
234649
234650
234651
......
235233
235234
235235
235236
235237
235238
235239
235240
235241
235242
235243
235244
235245
235246
235247
235248
235249
235250
......
235879
235880
235881
235882
235883
235884
235885
235886
235887
235888
235889
235890
235891
235892
235893
235894
235895
235896
......
236153
236154
236155
236156
236157
236158
236159
236160
236161
236162
236163
236164
236165
236166
236167
236168
236169
236170
......
241937
241938
241939
241940
241941
241942
241943
241944
241945
241946
241947
241948
241949
241950
241951
241952
241953
241954
......
244324
244325
244326
244327
244328
244329
244330
244331
244332
244333
244334
244335
244336
244337
244338
244339
244340
244341
......
244522
244523
244524
244525
244526
244527
244528
244529
244530
244531
244532
244533
244534
244535
244536
244537
244538
244539
......
246495
246496
246497
246498
246499
246500
246501
246502
246503
246504
246505
246506
246507
246508
246509
246510
246511
246512
246513
246514
......
250628
250629
250630
250631
250632
250633
250634
250635
250636
250637
250638
250639
250640
250641
250642
250643
250644
250645
......
251306
251307
251308
251309
251310
251311
251312
251313
251314
251315
251316
251317
251318
251319
251320
251321
251322
251323
......
251469
251470
251471
251472
251473
251474
251475
251476
251477
251478
251479
251480
251481
251482
251483
251484
251485
251486
......
251619
251620
251621
251622
251623
251624
251625
251626
251627
251628
251629
251630
251631
251632
251633
251634
251635
251636
......
253647
253648
253649
253650
253651
253652
253653
253654
253655
253656
253657
253658
253659
253660
253661
253662
253663
253664
_	nom adj epi sg	abdicataire
_	nom adj epi pl	abdicataires
$
abdication	S*()
_	nom fem sg	abdication
_	nom fem pl	abdications
$
abdo	S*()
_	nom mas sg	abdo
_	nom mas pl	abdos
$
abdomen	S*()
_	nom mas sg	abdomen
_	nom mas pl	abdomens
$
abdominal	X*()
_	nom mas sg	abdominal
_	nom mas pl	abdominaux
................................................................................
_	adj epi sg	acathiste
_	adj epi pl	acathistes
$
acaule	S*()
_	adj epi sg	acaule
_	adj epi pl	acaules
$
acausale	W*()
_	adj fem sg	acausale
_	adj fem pl	acausales
_	adj mas sg	acausal
_	adj mas pl	acausaux
$
accablante	F*()
_	nom adj fem sg	accablante
_	nom adj fem pl	accablantes
_	nom adj mas sg	accablant
_	nom adj mas pl	accablants
$
accablement	S*()
................................................................................
$
addictive	F*()
_	adj fem sg	addictive
_	adj fem pl	addictives
_	adj mas sg	addictif
_	adj mas pl	addictifs
$
addictogène	S*()
_	adj epi sg	addictogène
_	adj epi pl	addictogènes
$
addictologie	S*()
_	nom fem sg	addictologie
_	nom fem pl	addictologies
$
addictologique	S*()
_	adj epi sg	addictologique
_	adj epi pl	addictologiques
................................................................................
_	nom fem sg	adénomectomie
_	nom fem pl	adénomectomies
$
adénopathie	S*()
_	nom fem sg	adénopathie
_	nom fem pl	adénopathies
$
adénosarcome	S*()
_	nom mas sg	adénosarcome
_	nom mas pl	adénosarcomes
$
adénosine	S*()
_	nom fem sg	adénosine
_	nom fem pl	adénosines
$
adénovirale	W*()
_	adj fem sg	adénovirale
_	adj fem pl	adénovirales
................................................................................
$
antitussive	F*()
_	adj fem sg	antitussive
_	adj fem pl	antitussives
_	adj mas sg	antitussif
_	adj mas pl	antitussifs
$
antivaccin	S=
_	adj epi inv	antivaccin
_	adj epi inv	antivaccins
$
antivariolique	S*()
_	adj epi sg	antivariolique
_	adj epi pl	antivarioliques
$
antivénéneuse	W*()
_	adj fem sg	antivénéneuse
_	adj fem pl	antivénéneuses
................................................................................
_	nom fem sg	archi
_	nom fem pl	archis
$
archiatre	S*()
_	nom mas sg	archiatre
_	nom mas pl	archiatres
$
archibasilique	S*()
_	nom fem sg	archibasilique
_	nom fem pl	archibasiliques
$
archichancelier	S*()
_	nom mas sg	archichancelier
_	nom mas pl	archichanceliers
$
archiconfrérie	S*()
_	nom fem sg	archiconfrérie
_	nom fem pl	archiconfréries
................................................................................
_	adj mas sg	autocollant
_	adj mas pl	autocollants
$
autocommutateur	S*()
_	nom mas sg	autocommutateur
_	nom mas pl	autocommutateurs
$
autocomplétion	S*()
_	nom fem sg	autocomplétion
_	nom fem pl	autocomplétions
$
autoconcurrence	S*()
_	nom fem sg	autoconcurrence
_	nom fem pl	autoconcurrences
$
autoconditionnement	S*()
_	nom mas sg	autoconditionnement
_	nom mas pl	autoconditionnements
................................................................................
_	nom fem sg	autopatrouille
_	nom fem pl	autopatrouilles
$
autophagie	S*()
_	nom fem sg	autophagie
_	nom fem pl	autophagies
$
autophagique	S*()
_	adj epi sg	autophagique
_	adj epi pl	autophagiques
$
autopilote	S*()
_	nom mas sg	autopilote
_	nom mas pl	autopilotes
$
autopilotée	F*()
_	adj fem sg	autopilotée
_	adj fem pl	autopilotées
................................................................................
_	nom adj mas sg	autrichien
_	nom adj mas pl	autrichiens
$
autruche	S*()
_	nom fem sg	autruche
_	nom fem pl	autruches
$
autruchon	S*()
_	nom mas sg	autruchon
_	nom mas pl	autruchons
$
autunite	S*()
_	nom fem sg	autunite
_	nom fem pl	autunites
$
auvent	S*()
_	nom mas sg	auvent
_	nom mas pl	auvents
................................................................................
_	nom mas sg	aviron
_	nom mas pl	avirons
$
avirulence	S*()
_	nom fem sg	avirulence
_	nom fem pl	avirulences
$
aviseur	S*()
_	nom mas sg	aviseur
_	nom mas pl	aviseurs
$
aviso	S*()
_	nom mas sg	aviso
_	nom mas pl	avisos
$
avitaillement	S*()
_	nom mas sg	avitaillement
_	nom mas pl	avitaillements
................................................................................
_	adj epi sg	axonométrique
_	adj epi pl	axonométriques
$
axopode	S*()
_	nom mas sg	axopode
_	nom mas pl	axopodes
$
ayahuasca	S*()
_	nom mas sg	ayahuasca
_	nom mas pl	ayahuascas
$
ayant	S*()
_	nom mas sg	ayant
_	nom mas pl	ayants
$
ayatollah	S*()
_	nom mas sg	ayatollah
_	nom mas pl	ayatollahs
................................................................................
_	nom mas sg	baguier
_	nom mas pl	baguiers
$
baguiste	S.()
_	nom epi sg	baguiste
_	nom epi pl	baguistes
$






bahaïe	F.()
_	nom adj fem sg	bahaïe
_	nom adj fem pl	bahaïes
_	nom adj mas sg	bahaï
_	nom adj mas pl	bahaïs
$




bahaïsme	S.()
_	nom mas sg	bahaïsme
_	nom mas pl	bahaïsmes
$
bahamienne	F.()
_	nom adj fem sg	bahamienne
_	nom adj fem pl	bahamiennes
_	nom adj mas sg	bahamien
_	nom adj mas pl	bahamiens
$
baha’ie	F.()
_	nom adj fem sg	baha’ie
_	nom adj fem pl	baha’ies
_	nom adj mas sg	baha’i
_	nom adj mas pl	baha’is
$
baha’isme	S.()
_	nom mas sg	baha’isme
_	nom mas pl	baha’ismes
$
bahreïnie	F.()
_	nom adj fem sg	bahreïnie
_	nom adj fem pl	bahreïnies
_	nom adj mas sg	bahreïni
_	nom adj mas pl	bahreïnis
$
baht	S.()
................................................................................
$
beugleuse	F.()
_	nom fem sg	beugleuse
_	nom fem pl	beugleuses
_	nom mas sg	beugleur
_	nom mas pl	beugleurs
$
beuh	S.()
_	nom fem sg	beuh
_	nom fem pl	beuhs
$
beur	S.()
_	nom adj epi sg	beur
_	nom adj epi pl	beurs
$
beurette	S.()
_	nom fem sg	beurette
_	nom fem pl	beurettes
................................................................................
_	nom epi sg	blitzkrieg
_	nom epi pl	blitzkriegs
$
blizzard	S.()
_	nom mas sg	blizzard
_	nom mas pl	blizzards
$
blob	S.()
_	nom mas sg	blob
_	nom mas pl	blobs
$
bloc	S.()
_	nom mas sg	bloc
_	nom mas pl	blocs
$
blocage	S.()
_	nom mas sg	blocage
_	nom mas pl	blocages
................................................................................
_	nom fem sg	bouillasse
_	nom fem pl	bouillasses
$
bouille	S.()
_	nom fem sg	bouille
_	nom fem pl	bouilles
$
bouillette	S.()
_	nom fem sg	bouillette
_	nom fem pl	bouillettes
$
bouilleuse	F.()
_	nom fem sg	bouilleuse
_	nom fem pl	bouilleuses
_	nom mas sg	bouilleur
_	nom mas pl	bouilleurs
$
bouillie	S.()
................................................................................
_	adj epi sg	branchiopode
_	adj epi pl	branchiopodes
$
branchiopode	S.()
_	nom mas sg	branchiopode
_	nom mas pl	branchiopodes
$
branchitude	S.()
_	nom fem sg	branchitude
_	nom fem pl	branchitudes
$
branchue	F.()
_	adj fem sg	branchue
_	adj fem pl	branchues
_	adj mas sg	branchu
_	adj mas pl	branchus
$
brandade	S.()
................................................................................
_	adj mas sg	brillant
_	adj mas pl	brillants
$
brillantine	S.()
_	nom fem sg	brillantine
_	nom fem pl	brillantines
$
brillantissime	S.()
_	adj epi sg	brillantissime
_	adj epi pl	brillantissimes
$
brimade	S.()
_	nom fem sg	brimade
_	nom fem pl	brimades
$
brimbalement	S.()
_	nom mas sg	brimbalement
_	nom mas pl	brimbalements
................................................................................
_	nom mas sg	bromoxynil
_	nom mas pl	bromoxynils
$
bromure	S.()
_	nom mas sg	bromure
_	nom mas pl	bromures
$
bronca	S.()
_	nom fem sg	bronca
_	nom fem pl	broncas
$
bronchade	S.()
_	nom fem sg	bronchade
_	nom fem pl	bronchades
$
bronche	S.()
_	nom fem sg	bronche
_	nom fem pl	bronches
................................................................................
_	nom mas sg	cadeau
_	nom mas pl	cadeaux
$
cadenassable	S.()
_	adj epi sg	cadenassable
_	adj epi pl	cadenassables
$
cadenassage	S.()
_	nom mas sg	cadenassage
_	nom mas pl	cadenassages
$
cadence	S.()
_	nom fem sg	cadence
_	nom fem pl	cadences
$
cadencement	S.()
_	nom mas sg	cadencement
_	nom mas pl	cadencements
................................................................................
_	nom fem sg	chapelure
_	nom fem pl	chapelures
$
chaperon	S.()
_	nom mas sg	chaperon
_	nom mas pl	chaperons
$
chaperonnage	S.()
_	nom mas sg	chaperonnage
_	nom mas pl	chaperonnages
$
chapiste	S.()
_	nom epi sg	chapiste
_	nom epi pl	chapistes
$
chapiteau	X.()
_	nom mas sg	chapiteau
_	nom mas pl	chapiteaux
................................................................................
$
chatteuse	F.()
_	nom fem sg	chatteuse
_	nom fem pl	chatteuses
_	nom mas sg	chatteur
_	nom mas pl	chatteurs
$
chaudasse	S.()
_	nom fem sg	chaudasse
_	nom fem pl	chaudasses
$
chaude	F.()
_	nom adj fem sg	chaude
_	nom adj fem pl	chaudes
_	nom adj mas sg	chaud
_	nom adj mas pl	chauds
$
chaudeau	X.()
................................................................................
_	nom adj epi sg	chti
_	nom adj epi pl	chtis
$
chtimi	S.()
_	nom adj epi sg	chtimi
_	nom adj epi pl	chtimis
$




chtonienne	F.()
_	adj fem sg	chtonienne
_	adj fem pl	chtoniennes
_	adj mas sg	chtonien
_	adj mas pl	chtoniens
$
chtouille	S.()
................................................................................
_	adj mas sg	chypré
_	adj mas pl	chyprés
$
chypriote	S.()
_	nom adj epi sg	chypriote
_	nom adj epi pl	chypriotes
$
ch’timi	S.()
_	nom adj epi sg	ch’timi
_	nom adj epi pl	ch’timis
$
ciabatta	S.()
_	nom fem sg	ciabatta
_	nom fem pl	ciabattas
$
cibiche	S.()
_	nom fem sg	cibiche
_	nom fem pl	cibiches
................................................................................
_	nom mas sg	contour
_	nom mas pl	contours
$
contournable	S.()
_	adj epi sg	contournable
_	adj epi pl	contournables
$
contournage	S.()
_	nom mas sg	contournage
_	nom mas pl	contournages
$
contournement	S.()
_	nom mas sg	contournement
_	nom mas pl	contournements
$
contraceptif	S.()
_	nom mas sg	contraceptif
_	nom mas pl	contraceptifs
................................................................................
_	nom mas sg	coran
_	nom mas pl	corans
$
coranique	S.()
_	adj epi sg	coranique
_	adj epi pl	coraniques
$
corapporteuse	F.()
_	nom adj fem sg	corapporteuse
_	nom adj fem pl	corapporteuses
_	nom adj mas sg	corapporteur
_	nom adj mas pl	corapporteurs
$
corb	S.()
_	nom mas sg	corb
_	nom mas pl	corbs
$
corbac	S.()
_	nom mas sg	corbac
_	nom mas pl	corbacs
................................................................................
$
correcte	F.()
_	adj fem sg	correcte
_	adj fem pl	correctes
_	adj mas sg	correct
_	adj mas pl	corrects
$
correcticiel	S.()
_	nom mas sg	correcticiel
_	nom mas pl	correcticiels
$
correctif	S.()
_	nom mas sg	correctif
_	nom mas pl	correctifs
$
correction	S.()
_	nom fem sg	correction
_	nom fem pl	corrections
................................................................................
_	nom mas sg	damalisque
_	nom mas pl	damalisques
$
daman	S.()
_	nom mas sg	daman
_	nom mas pl	damans
$
damascène	S.()
_	nom adj epi sg	damascène
_	nom adj epi pl	damascènes
$
damasquinage	S.()
_	nom mas sg	damasquinage
_	nom mas pl	damasquinages
$
damasquinerie	S.()
_	nom fem sg	damasquinerie
_	nom fem pl	damasquineries
................................................................................
_	adj epi sg	déblocable
_	adj epi pl	déblocables
$
déblocage	S.()
_	nom mas sg	déblocage
_	nom mas pl	déblocages
$
débobinage	S.()
_	nom mas sg	débobinage
_	nom mas pl	débobinages
$
débogage	S.()
_	nom mas sg	débogage
_	nom mas pl	débogages
$
débogueur	S.()
_	nom mas sg	débogueur
_	nom mas pl	débogueurs
................................................................................
_	adj mas sg	décisif
_	adj mas pl	décisifs
$
décisoire	S.()
_	adj epi sg	décisoire
_	adj epi pl	décisoires
$
décivilisation	S.()
_	nom fem sg	décivilisation
_	nom fem pl	décivilisations
$
déclamation	S.()
_	nom fem sg	déclamation
_	nom fem pl	déclamations
$
déclamatoire	S.()
_	adj epi sg	déclamatoire
_	adj epi pl	déclamatoires
................................................................................
_	nom fem sg	dédifférenciation
_	nom fem pl	dédifférenciations
$
dédit	S.()
_	nom mas sg	dédit
_	nom mas pl	dédits
$
dédollarisation	S.()
_	nom fem sg	dédollarisation
_	nom fem pl	dédollarisations
$
dédommagement	S.()
_	nom mas sg	dédommagement
_	nom mas pl	dédommagements
$
dédorage	S.()
_	nom mas sg	dédorage
_	nom mas pl	dédorages
................................................................................
_	nom mas sg	démariage
_	nom mas pl	démariages
$
démarquage	S.()
_	nom mas sg	démarquage
_	nom mas pl	démarquages
$
démarque	S.()
_	nom epi sg	démarque
_	nom epi pl	démarques
$
démarqueuse	F.()
_	nom fem sg	démarqueuse
_	nom fem pl	démarqueuses
_	nom mas sg	démarqueur
_	nom mas pl	démarqueurs
$
démarrage	S.()
................................................................................
_	nom mas sg	dépolissage
_	nom mas pl	dépolissages
$
dépolitisation	S.()
_	nom fem sg	dépolitisation
_	nom fem pl	dépolitisations
$
dépolluante	F.()
_	adj fem sg	dépolluante
_	adj fem pl	dépolluantes
_	adj mas sg	dépolluant
_	adj mas pl	dépolluants
$
dépollution	S.()
_	nom fem sg	dépollution
_	nom fem pl	dépollutions
$
dépolymérisation	S.()
_	nom fem sg	dépolymérisation
_	nom fem pl	dépolymérisations
................................................................................
_	nom mas sg	déprimé
_	nom mas pl	déprimés
$
déprimogène	S.()
_	adj epi sg	déprimogène
_	adj epi pl	déprimogènes
$
déprofessionnalisation	S.()
_	nom fem sg	déprofessionnalisation
_	nom fem pl	déprofessionnalisations
$
déprogrammation	S.()
_	nom fem sg	déprogrammation
_	nom fem pl	déprogrammations
$
déprolétarisation	S.()
_	nom fem sg	déprolétarisation
_	nom fem pl	déprolétarisations
................................................................................
_	nom epi sg	dogmatiste
_	nom epi pl	dogmatistes
$
dogme	S.()
_	nom mas sg	dogme
_	nom mas pl	dogmes
$
dogonne	F.()
_	nom adj fem sg	dogonne
_	nom adj fem pl	dogonnes
_	nom adj mas sg	dogon
_	nom adj mas pl	dogons
$
dogue	S.()
_	nom mas sg	dogue
_	nom mas pl	dogues
$
doigt	S.()
_	nom mas sg	doigt
_	nom mas pl	doigts
................................................................................
_	nom epi sg	droguiste
_	nom epi pl	droguistes
$
droïde	S.()
_	nom mas sg	droïde
_	nom mas pl	droïdes
$
droit-de-lhommisme	S.()
_	nom mas sg	droit-de-lhommisme
_	nom mas pl	droit-de-lhommismes
$
droit-de-lhommiste	S.()
_	nom adj epi sg	droit-de-lhommiste
_	nom adj epi pl	droit-de-lhommistes
$
droite	F.()
_	nom adj fem sg	droite
_	nom adj fem pl	droites
_	nom adj mas sg	droit
_	nom adj mas pl	droits
$
................................................................................
_	nom mas sg	écœurement
_	nom mas pl	écœurements
$
écogeste	S*()
_	nom mas sg	écogeste
_	nom mas pl	écogestes
$
éco-gestion	S*()
_	nom fem sg	éco-gestion
_	nom fem pl	éco-gestions
$
écohabitat	S*()
_	nom mas sg	écohabitat
_	nom mas pl	écohabitats
$
écoinçon	S*()
_	nom mas sg	écoinçon
_	nom mas pl	écoinçons
................................................................................
_	nom fem sg	électroencéphalographie
_	nom fem pl	électroencéphalographies
$
électro-encéphalographie	S*()
_	nom fem sg	électro-encéphalographie
_	nom fem pl	électro-encéphalographies
$
électroérosion	S*()
_	nom fem sg	électroérosion
_	nom fem pl	électroérosions
$
électro-érosion	S*()
_	nom fem sg	électro-érosion
_	nom fem pl	électro-érosions
$
électrofaible	S*()
_	adj epi sg	électrofaible
_	adj epi pl	électrofaibles
$
électro-faible	S*()
_	adj epi sg	électro-faible
_	adj epi pl	électro-faibles
................................................................................
_	nom mas sg	étendoir
_	nom mas pl	étendoirs
$
étendue	S*()
_	nom fem sg	étendue
_	nom fem pl	étendues
$
éternalisme	S*()
_	nom mas sg	éternalisme
_	nom mas pl	éternalismes
$
éternelle	F*()
_	adj fem sg	éternelle
_	adj fem pl	éternelles
_	adj mas sg	éternel
_	adj mas pl	éternels
$
éternité	S*()
................................................................................
_	nom mas sg	exondement
_	nom mas pl	exondements
$
exonération	S*()
_	nom fem sg	exonération
_	nom fem pl	exonérations
$
exonératoire	S*()
_	adj epi sg	exonératoire
_	adj epi pl	exonératoires
$
exonyme	S*()
_	nom mas sg	exonyme
_	nom mas pl	exonymes
$
exonymie	S*()
_	nom fem sg	exonymie
_	nom fem pl	exonymies
................................................................................
_	nom fem sg	extrémité
_	nom fem pl	extrémités
$
extrémophile	S*()
_	nom adj epi sg	extrémophile
_	nom adj epi pl	extrémophiles
$
extremum	I*()
_	nom mas sg	extremum
_	nom mas pl	extremums
_	nom mas pl	extrema
$
extrémum	S*()
_	nom mas sg	extrémum
_	nom mas pl	extrémums
$
extrinsécisme	S*()
_	nom mas sg	extrinsécisme
................................................................................
_	nom fem pl	finances
$
financement	S.()
_	nom mas sg	financement
_	nom mas pl	financements
$
financeuse	F.()
_	nom adj fem sg	financeuse
_	nom adj fem pl	financeuses
_	nom adj mas sg	financeur
_	nom adj mas pl	financeurs
$
financiarisation	S.()
_	nom fem sg	financiarisation
_	nom fem pl	financiarisations
$
financiarisme	S.()
_	nom mas sg	financiarisme
................................................................................
_	nom fem sg	gayolle
_	nom fem pl	gayolles
$
gazage	S.()
_	nom mas sg	gazage
_	nom mas pl	gazages
$
gazaouie	F.()
_	nom adj fem sg	gazaouie
_	nom adj fem pl	gazaouies
_	nom adj mas sg	gazaoui
_	nom adj mas pl	gazaouis
$
gaze	S.()
_	nom fem sg	gaze
_	nom fem pl	gazes
$
gazée	F.()
_	nom fem sg	gazée
_	nom fem pl	gazées
................................................................................
_	nom fem sg	gougnote
_	nom fem pl	gougnotes
$
gougnotte	S.()
_	nom fem sg	gougnotte
_	nom fem pl	gougnottes
$
gouinasse	S.()
_	nom fem sg	gouinasse
_	nom fem pl	gouinasses
$
gouine	S.()
_	nom fem sg	gouine
_	nom fem pl	gouines
$
goujat	S.()
_	nom mas sg	goujat
_	nom mas pl	goujats
................................................................................
_	nom mas sg	gratteur
_	nom mas pl	gratteurs
$
grattoir	S.()
_	nom mas sg	grattoir
_	nom mas pl	grattoirs
$
gratton	S.()
_	nom mas sg	gratton
_	nom mas pl	grattons
$
grattouille	S.()
_	nom fem sg	grattouille
_	nom fem pl	grattouilles
$
gratture	S.()
_	nom fem sg	gratture
_	nom fem pl	grattures
................................................................................
_	adj epi sg	hégémonique
_	adj epi pl	hégémoniques
$
hégémonisme	S*()
_	nom mas sg	hégémonisme
_	nom mas pl	hégémonismes
$
hégémoniste	S*()
_	nom adj epi sg	hégémoniste
_	nom adj epi pl	hégémonistes
$
hégire	S*()
_	nom fem sg	hégire
_	nom fem pl	hégires
$
hégirienne	F*()
_	adj fem sg	hégirienne
_	adj fem pl	hégiriennes
................................................................................
_	nom mas sg	hihan
_	nom mas pl	hihans
$
hijab	S.()
_	nom mas sg	hijab
_	nom mas pl	hijabs
$
hikikomori	S*()
_	nom epi sg	hikikomori
_	nom epi pl	hikikomoris
$
hilaire	S.()
_	adj epi sg	hilaire
_	adj epi pl	hilaires
$
hilarante	F*()
_	adj fem sg	hilarante
_	adj fem pl	hilarantes
................................................................................
_	adj epi sg	hyperchrome
_	adj epi pl	hyperchromes
$
hyperchromie	S*()
_	nom fem sg	hyperchromie
_	nom fem pl	hyperchromies
$
hypercoagulabilité	S*()
_	nom fem sg	hypercoagulabilité
_	nom fem pl	hypercoagulabilités
$
hypercomplexe	S*()
_	adj epi sg	hypercomplexe
_	adj epi pl	hypercomplexes
$
hyperconformisme	S*()
_	nom mas sg	hyperconformisme
_	nom mas pl	hyperconformismes
................................................................................
$
hypercontinentale	W*()
_	adj fem sg	hypercontinentale
_	adj fem pl	hypercontinentales
_	adj mas sg	hypercontinental
_	adj mas pl	hypercontinentaux
$
hypercontrôle	S*()
_	nom mas sg	hypercontrôle
_	nom mas pl	hypercontrôles
$
hypercorrecte	F*()
_	adj fem sg	hypercorrecte
_	adj fem pl	hypercorrectes
_	adj mas sg	hypercorrect
_	adj mas pl	hypercorrects
$
hypercorrection	S*()
................................................................................
_	adj epi sg	hyperonymique
_	adj epi pl	hyperonymiques
$
hyperostose	S*()
_	nom fem sg	hyperostose
_	nom fem pl	hyperostoses
$
hyperoxie	S*()
_	nom fem sg	hyperoxie
_	nom fem pl	hyperoxies
$
hyperparasite	S*()
_	nom mas sg	hyperparasite
_	nom mas pl	hyperparasites
$
hyperparathyroïdie	S*()
_	nom fem sg	hyperparathyroïdie
_	nom fem pl	hyperparathyroïdies
................................................................................
_	nom fem sg	hyperplasie
_	nom fem pl	hyperplasies
$
hyperplasique	S*()
_	adj epi sg	hyperplasique
_	adj epi pl	hyperplasiques
$
hyperproductivité	S*()
_	nom fem sg	hyperproductivité
_	nom fem pl	hyperproductivités
$
hyperprolactinémie	S*()
_	nom fem sg	hyperprolactinémie
_	nom fem pl	hyperprolactinémies
$
hyperpuissance	S*()
_	nom fem sg	hyperpuissance
_	nom fem pl	hyperpuissances
................................................................................
_	adj mas sg	impératif
_	adj mas pl	impératifs
$
impératrice	S*()
_	nom fem sg	impératrice
_	nom fem pl	impératrices
$
imperçable	S*()
_	adj epi sg	imperçable
_	adj epi pl	imperçables
$
imperceptibilité	S*()
_	nom fem sg	imperceptibilité
_	nom fem pl	imperceptibilités
$
imperceptible	S*()
_	adj epi sg	imperceptible
_	adj epi pl	imperceptibles
................................................................................
_	nom fem sg	imprescriptibilité
_	nom fem pl	imprescriptibilités
$
imprescriptible	S*()
_	adj epi sg	imprescriptible
_	adj epi pl	imprescriptibles
$
imprésentable	S*()
_	adj epi sg	imprésentable
_	adj epi pl	imprésentables
$
impression	S*()
_	nom fem sg	impression
_	nom fem pl	impressions
$
impressionnabilité	S*()
_	nom fem sg	impressionnabilité
_	nom fem pl	impressionnabilités
................................................................................
_	adj epi sg	increvable
_	adj epi pl	increvables
$
incriminable	S*()
_	adj epi sg	incriminable
_	adj epi pl	incriminables
$
incriminante	F*()
_	adj fem sg	incriminante
_	adj fem pl	incriminantes
_	adj mas sg	incriminant
_	adj mas pl	incriminants
$
incrimination	S*()
_	nom fem sg	incrimination
_	nom fem pl	incriminations
$
incristallisable	S*()
_	adj epi sg	incristallisable
_	adj epi pl	incristallisables
................................................................................
_	nom adj mas sg	jamaïquain
_	nom adj mas pl	jamaïquains
$
jambage	S.()
_	nom mas sg	jambage
_	nom mas pl	jambages
$
jambalaya	S.()
_	nom mas sg	jambalaya
_	nom mas pl	jambalayas
$
jambart	S.()
_	nom mas sg	jambart
_	nom mas pl	jambarts
$
jambe	S.()
_	nom fem sg	jambe
_	nom fem pl	jambes
................................................................................
_	nom mas sg	jéjuno-iléon
_	nom mas pl	jéjuno-iléons
$
jéjunum	S.()
_	nom mas sg	jéjunum
_	nom mas pl	jéjunums
$
je-men-fichisme	S.()
_	nom mas sg	je-men-fichisme
_	nom mas pl	je-men-fichismes
$
je-men-fichiste	S.()
_	nom adj epi sg	je-men-fichiste
_	nom adj epi pl	je-men-fichistes
$
je-men-foutisme	S.()
_	nom mas sg	je-men-foutisme
_	nom mas pl	je-men-foutismes
$
je-men-foutiste	S.()
_	nom adj epi sg	je-men-foutiste
_	nom adj epi pl	je-men-foutistes
$
jennérienne	F.()
_	adj fem sg	jennérienne
_	adj fem pl	jennériennes
_	adj mas sg	jennérien
_	adj mas pl	jennériens
$
................................................................................
_	nom mas sg	jusnaturalisme
_	nom mas pl	jusnaturalismes
$
jusnaturaliste	S.()
_	nom adj epi sg	jusnaturaliste
_	nom adj epi pl	jusnaturalistes
$








jusquiame	S.()
_	nom fem sg	jusquiame
_	nom fem pl	jusquiames
$
jusqu’au-boutisme	S.()
_	nom mas sg	jusqu’au-boutisme
_	nom mas pl	jusqu’au-boutismes
$
jusqu’au-boutiste	S.()
_	nom epi sg	jusqu’au-boutiste
_	nom epi pl	jusqu’au-boutistes
$
jussiée	S.()
_	nom fem sg	jussiée
_	nom fem pl	jussiées
$
jussion	S.()
_	nom fem sg	jussion
_	nom fem pl	jussions
................................................................................
_	adj epi sg	magnétoélectrique
_	adj epi pl	magnétoélectriques
$
magnéto-électrique	S.()
_	adj epi sg	magnéto-électrique
_	adj epi pl	magnéto-électriques
$
magnétoformage	S.()
_	nom mas sg	magnétoformage
_	nom mas pl	magnétoformages
$
magnétogaine	S.()
_	nom fem sg	magnétogaine
_	nom fem pl	magnétogaines
$
magnétohydrodynamique	S.()
_	adj epi sg	magnétohydrodynamique
_	adj epi pl	magnétohydrodynamiques
................................................................................
_	nom mas sg	mammouth
_	nom mas pl	mammouths
$
mammy	S.()
_	nom fem sg	mammy
_	nom fem pl	mammys
$




mamy	S.()
_	nom fem sg	mamy
_	nom fem pl	mamys
$
mam’selle	S.()
_	nom fem sg	mam’selle
_	nom fem pl	mam’selles
$
mamzelle	S.()
_	nom fem sg	mamzelle
_	nom fem pl	mamzelles
$
man	S.()
_	nom mas sg	man
_	nom mas pl	mans
$
mana	S.()
_	nom mas sg	mana
................................................................................
$
marchandeuse	F.()
_	nom fem sg	marchandeuse
_	nom fem pl	marchandeuses
_	nom mas sg	marchandeur
_	nom mas pl	marchandeurs
$
marchandisable	S.()
_	adj epi sg	marchandisable
_	adj epi pl	marchandisables
$
marchandisage	S.()
_	nom mas sg	marchandisage
_	nom mas pl	marchandisages
$
marchandisation	S.()
_	nom fem sg	marchandisation
_	nom fem pl	marchandisations
................................................................................
_	nom mas sg	méaculpa
_	nom mas pl	méaculpas
$
méandre	S.()
_	nom mas sg	méandre
_	nom mas pl	méandres
$
méandreuse	W.()
_	adj fem sg	méandreuse
_	adj fem pl	méandreuses
_	adj mas inv	méandreux
$
méandriforme	S.()
_	adj epi sg	méandriforme
_	adj epi pl	méandriformes
$
méandrine	S.()
_	nom fem sg	méandrine
_	nom fem pl	méandrines
................................................................................
_	nom fem sg	mésalliance
_	nom fem pl	mésalliances
$
mésange	S.()
_	nom fem sg	mésange
_	nom fem pl	mésanges
$
mésangeai	S.()
_	nom mas sg	mésangeai
_	nom mas pl	mésangeais
$
mésangette	S.()
_	nom fem sg	mésangette
_	nom fem pl	mésangettes
$
mésappariement	S.()
_	nom mas sg	mésappariement
_	nom mas pl	mésappariements
................................................................................
_	adj mas sg	mesmérien
_	adj mas pl	mesmériens
$
mesmérisme	S.()
_	nom mas sg	mesmérisme
_	nom mas pl	mesmérismes
$
mésoaméricaine	F.()
_	nom adj fem sg	mésoaméricaine
_	nom adj fem pl	mésoaméricaines
_	nom adj mas sg	mésoaméricain
_	nom adj mas pl	mésoaméricains
$
mésoblaste	S.()
_	nom mas sg	mésoblaste
_	nom mas pl	mésoblastes
$
mésoblastique	S.()
_	adj epi sg	mésoblastique
_	adj epi pl	mésoblastiques
................................................................................
_	adj mas sg	microlocalisé
_	adj mas pl	microlocalisés
$
micrologiciel	S.()
_	nom mas sg	micrologiciel
_	nom mas pl	micrologiciels
$
micromachine	S.()
_	nom fem sg	micromachine
_	nom fem pl	micromachines
$
micromanipulateur	S.()
_	nom mas sg	micromanipulateur
_	nom mas pl	micromanipulateurs
$
micromanipulation	S.()
_	nom fem sg	micromanipulation
_	nom fem pl	micromanipulations
$
micromécanique	S.()
_	nom fem sg	micromécanique
_	nom fem pl	micromécaniques
$
micromélange	S.()
_	nom mas sg	micromélange
_	nom mas pl	micromélanges
$
micromélangeage	S.()
_	nom mas sg	micromélangeage
_	nom mas pl	micromélangeages
................................................................................
_	nom mas sg	monocamérisme
_	nom mas pl	monocamérismes
$
monocarboxylique	S.()
_	adj epi sg	monocarboxylique
_	adj epi pl	monocarboxyliques
$
monocarte	S.()
_	adj epi sg	monocarte
_	adj epi pl	monocartes
$
monocaténaire	S.()
_	adj epi sg	monocaténaire
_	adj epi pl	monocaténaires
$
monocellulaire	S.()
_	adj epi sg	monocellulaire
_	adj epi pl	monocellulaires
................................................................................
_	adj epi sg	néphrotique
_	adj epi pl	néphrotiques
$
néphrotoxique	S.()
_	adj epi sg	néphrotoxique
_	adj epi pl	néphrotoxiques
$
népotique	S.()
_	adj epi sg	népotique
_	adj epi pl	népotiques
$
népotisme	S.()
_	nom mas sg	népotisme
_	nom mas pl	népotismes
$
neptunium	S.()
_	nom mas sg	neptunium
_	nom mas pl	neptuniums
................................................................................
_	nom epi sg	neuroanatomiste
_	nom epi pl	neuroanatomistes
$
neuro-anatomiste	S.()
_	nom epi sg	neuro-anatomiste
_	nom epi pl	neuro-anatomistes
$
neuroatypique	S.()
_	adj epi sg	neuroatypique
_	adj epi pl	neuroatypiques
$
neuro-atypique	S.()
_	adj epi sg	neuro-atypique
_	adj epi pl	neuro-atypiques
$
neurobiochimie	S.()
_	nom fem sg	neurobiochimie
_	nom fem pl	neurobiochimies
$
neurobiochimique	S.()
_	adj epi sg	neurobiochimique
_	adj epi pl	neurobiochimiques
................................................................................
_	nom fem sg	orchidacée
_	nom fem pl	orchidacées
$
orchidée	S*()
_	nom fem sg	orchidée
_	nom fem pl	orchidées
$
orchidologie	S*()
_	nom fem sg	orchidologie
_	nom fem pl	orchidologies
$
orchiépididymite	S*()
_	nom fem sg	orchiépididymite
_	nom fem pl	orchiépididymites
$
orchi-épididymite	S*()
_	nom fem sg	orchi-épididymite
_	nom fem pl	orchi-épididymites
................................................................................
_	nom fem sg	pala
_	nom fem pl	palas
$
palabre	S.()
_	nom epi sg	palabre
_	nom epi pl	palabres
$
palabreuse	F.()
_	nom fem sg	palabreuse
_	nom fem pl	palabreuses
_	nom mas sg	palabreur
_	nom mas pl	palabreurs
$
palace	S.()
_	nom mas sg	palace
_	nom mas pl	palaces
$
paladin	S.()
_	nom mas sg	paladin
_	nom mas pl	paladins
................................................................................
_	nom fem sg	parisette
_	nom fem pl	parisettes
$
parisianisme	S.()
_	nom mas sg	parisianisme
_	nom mas pl	parisianismes
$
parisianiste	S.()
_	adj epi sg	parisianiste
_	adj epi pl	parisianistes
$
parisienne	F.()
_	nom adj fem sg	parisienne
_	nom adj fem pl	parisiennes
_	nom adj mas sg	parisien
_	nom adj mas pl	parisiens
$
parisyllabique	S.()
................................................................................
$
pénale	W.()
_	adj fem sg	pénale
_	adj fem pl	pénales
_	adj mas sg	pénal
_	adj mas pl	pénaux
$
pénalisable	S.()
_	adj epi sg	pénalisable
_	adj epi pl	pénalisables
$
pénalisante	F.()
_	adj fem sg	pénalisante
_	adj fem pl	pénalisantes
_	adj mas sg	pénalisant
_	adj mas pl	pénalisants
$
pénalisation	S.()
................................................................................
_	nom mas sg	péramèle
_	nom mas pl	péramèles
$
perborate	S.()
_	nom mas sg	perborate
_	nom mas pl	perborates
$
perçable	S.()
_	adj epi sg	perçable
_	adj epi pl	perçables
$
perçage	S.()
_	nom mas sg	perçage
_	nom mas pl	perçages
$
percale	S.()
_	nom epi sg	percale
_	nom epi pl	percales
................................................................................
_	nom fem pl	pétéchies
$
pétersbourgeoise	F.()
_	nom adj fem sg	pétersbourgeoise
_	nom adj fem pl	pétersbourgeoises
_	nom adj mas inv	pétersbourgeois
$




péteuse	F.()
_	nom fem sg	péteuse
_	nom fem pl	péteuses
_	nom mas sg	péteur
_	nom mas pl	péteurs
$
péteuse	W.()
................................................................................
_	nom mas pl	piémonts
$
piémontaise	F.()
_	nom adj fem sg	piémontaise
_	nom adj fem pl	piémontaises
_	nom adj mas inv	piémontais
$
pier	S.()
_	nom mas sg	pier
_	nom mas pl	piers
$
piercing	S.()
_	nom mas sg	piercing
_	nom mas pl	piercings
$
piéride	S.()
_	nom fem sg	piéride
_	nom fem pl	piérides
................................................................................
$
politico-financière	F.()
_	adj fem sg	politico-financière
_	adj fem pl	politico-financières
_	adj mas sg	politico-financier
_	adj mas pl	politico-financiers
$
politico-judiciaire	S.()
_	adj epi sg	politico-judiciaire
_	adj epi pl	politico-judiciaires
$
politicologue	S.()
_	nom epi sg	politicologue
_	nom epi pl	politicologues
$
politico-médiatique	S.()
_	adj epi sg	politico-médiatique
_	adj epi pl	politico-médiatiques
................................................................................
$
présentielle	F.()
_	nom adj fem sg	présentielle
_	nom adj fem pl	présentielles
_	nom adj mas sg	présentiel
_	nom adj mas pl	présentiels
$
présentisme	S.()
_	nom mas sg	présentisme
_	nom mas pl	présentismes
$
présentoir	S.()
_	nom mas sg	présentoir
_	nom mas pl	présentoirs
$
présérie	S.()
_	nom fem sg	présérie
_	nom fem pl	préséries
................................................................................
_	nom fem sg	présidentialisation
_	nom fem pl	présidentialisations
$
présidentialisme	S.()
_	nom mas sg	présidentialisme
_	nom mas pl	présidentialismes
$
présidentialiste	S.()
_	nom adj epi sg	présidentialiste
_	nom adj epi pl	présidentialistes
$
présidentielle	F.()
_	adj fem sg	présidentielle
_	adj fem pl	présidentielles
_	adj mas sg	présidentiel
_	adj mas pl	présidentiels
$
présidial	X.()
................................................................................
_	nom adj fem pl	présomptueuses
_	nom adj mas inv	présomptueux
$
présonorisation	S.()
_	nom fem sg	présonorisation
_	nom fem pl	présonorisations
$
presquile	S.()
_	nom fem sg	presquile
_	nom fem pl	presquiles
$
presquîle	S.()
_	nom fem sg	presquîle
_	nom fem pl	presquîles
$
pressabilité	S.()
_	nom fem sg	pressabilité
_	nom fem pl	pressabilités
$
pressage	S.()
_	nom mas sg	pressage
................................................................................
_	adj mas sg	prudentiel
_	adj mas pl	prudentiels
$
pruderie	S.()
_	nom fem sg	pruderie
_	nom fem pl	pruderies
$










prudhommale	W.()
_	adj fem sg	prudhommale
_	adj fem pl	prudhommales
_	adj mas sg	prudhommal
_	adj mas pl	prudhommaux
$
prudhomme	S.()
_	nom mas sg	prudhomme
_	nom mas pl	prudhommes
$




prudhommerie	S.()
_	nom fem sg	prudhommerie
_	nom fem pl	prudhommeries
$
prudhommesque	S.()
_	adj epi sg	prudhommesque
_	adj epi pl	prudhommesques
$
prudhommie	S.()
_	nom fem sg	prudhommie
_	nom fem pl	prudhommies
$
prud’homale	W.()
_	adj fem sg	prud’homale
_	adj fem pl	prud’homales
_	adj mas sg	prud’homal
_	adj mas pl	prud’homaux
$
prud’homie	S.()
_	nom fem sg	prud’homie
_	nom fem pl	prud’homies
$
prud’homme	S.()
_	nom mas sg	prud’homme
_	nom mas pl	prud’hommes
$
pruine	S.()
_	nom fem sg	pruine
_	nom fem pl	pruines
$
prune	S.()
_	nom epi sg	prune
_	nom epi pl	prunes
................................................................................
_	adj mas sg	ptérygoïdien
_	adj mas pl	ptérygoïdiens
$
ptérygote	S.()
_	nom mas sg	ptérygote
_	nom mas pl	ptérygotes
$






ptolémaïque	S.()
_	adj epi sg	ptolémaïque
_	adj epi pl	ptolémaïques
$
ptoléméenne	F.()
_	adj fem sg	ptoléméenne
_	adj fem pl	ptoléméennes
................................................................................
_	nom fem sg	pyélonéphrite
_	nom fem pl	pyélonéphrites
$
pygargue	S.()
_	nom mas sg	pygargue
_	nom mas pl	pygargues
$
pygmalionisme	S.()
_	nom mas sg	pygmalionisme
_	nom mas pl	pygmalionismes
$
pygmée	S.()
_	nom adj epi sg	pygmée
_	nom adj epi pl	pygmées
$
pygméenne	F.()
_	adj fem sg	pygméenne
_	adj fem pl	pygméennes
................................................................................
_	nom fem sg	pyurie
_	nom fem pl	pyuries
$
pyxide	S.()
_	nom fem sg	pyxide
_	nom fem pl	pyxides
$
p’tite	F.()
_	nom adj fem sg	p’tite
_	nom adj fem pl	p’tites
_	nom adj mas sg	p’tit
_	nom adj mas pl	p’tits
$
qanat	S.()
_	nom mas sg	qanat
_	nom mas pl	qanats
$
qat	S.()
_	nom mas sg	qat
_	nom mas pl	qats
................................................................................
_	nom fem sg	ratification
_	nom fem pl	ratifications
$
ratinage	S.()
_	nom mas sg	ratinage
_	nom mas pl	ratinages
$
ratine	S.()
_	nom fem sg	ratine
_	nom fem pl	ratines
$
rating	S.()
_	nom mas sg	rating
_	nom mas pl	ratings
$
ratio	S.()
_	nom mas sg	ratio
_	nom mas pl	ratios
................................................................................
_	nom mas sg	recéleur
_	nom mas pl	recéleurs
$
récence	S.()
_	nom fem sg	récence
_	nom fem pl	récences
$
recensable	S.()
_	adj epi sg	recensable
_	adj epi pl	recensables
$
recensement	S.()
_	nom mas sg	recensement
_	nom mas pl	recensements
$
recenseuse	F.()
_	nom fem sg	recenseuse
_	nom fem pl	recenseuses
................................................................................
$
recycleuse	F.()
_	nom adj fem sg	recycleuse
_	nom adj fem pl	recycleuses
_	nom adj mas sg	recycleur
_	nom adj mas pl	recycleurs
$
rédac-chef	S.()
_	nom epi sg	rédac-chef
_	nom epi pl	rédac-chefs
$
rédaction	S.()
_	nom fem sg	rédaction
_	nom fem pl	rédactions
$
rédactionnel	S.()
_	nom mas sg	rédactionnel
_	nom mas pl	rédactionnels
................................................................................
rédemptrice	F.()
_	nom adj fem sg	rédemptrice
_	nom adj fem pl	rédemptrices
_	nom adj mas sg	rédempteur
_	nom adj mas pl	rédempteurs
$
redénomination	S.()
_	nom fem sg	redénomination
_	nom fem pl	redénominations
$
redent	S.()
_	nom mas sg	redent
_	nom mas pl	redents
$
redentée	F.()
_	adj fem sg	redentée
................................................................................
$
remblayeuse	F.()
_	nom fem sg	remblayeuse
_	nom fem pl	remblayeuses
_	nom mas sg	remblayeur
_	nom mas pl	remblayeurs
$
rembobinage	S.()
_	nom mas sg	rembobinage
_	nom mas pl	rembobinages
$
remboitage	S.()
_	nom mas sg	remboitage
_	nom mas pl	remboitages
$
remboîtage	S.()
_	nom mas sg	remboîtage
_	nom mas pl	remboîtages
................................................................................
$
ressortissante	F.()
_	nom adj fem sg	ressortissante
_	nom adj fem pl	ressortissantes
_	nom adj mas sg	ressortissant
_	nom adj mas pl	ressortissants
$
ressoudure	S.()
_	nom fem sg	ressoudure
_	nom fem pl	ressoudures
$
ressource	S.()
_	nom fem sg	ressource
_	nom fem pl	ressources
$
ressourcement	S.()
_	nom mas sg	ressourcement
_	nom mas pl	ressourcements
................................................................................
$
russo-turque	F.()
_	nom adj fem sg	russo-turque
_	nom adj fem pl	russo-turques
_	nom adj mas sg	russo-turc
_	nom adj mas pl	russo-turcs
$
russo-ukrainienne	F.()
_	nom adj fem sg	russo-ukrainienne
_	nom adj fem pl	russo-ukrainiennes
_	nom adj mas sg	russo-ukrainien
_	nom adj mas pl	russo-ukrainiens
$
russule	S.()
_	nom fem sg	russule
_	nom fem pl	russules
$
rustaude	F.()
_	nom adj fem sg	rustaude
_	nom adj fem pl	rustaudes
................................................................................
_	adj epi sg	sadique
_	adj epi pl	sadiques
$
sadisme	S.()
_	nom mas sg	sadisme
_	nom mas pl	sadismes
$
sado-maso	S.()
_	nom adj epi sg	sado-maso
_	nom adj epi pl	sado-masos
$
sadomasochisme	S.()
_	nom mas sg	sadomasochisme
_	nom mas pl	sadomasochismes
$
sado-masochisme	S.()
_	nom mas sg	sado-masochisme
_	nom mas pl	sado-masochismes
................................................................................
_	nom mas sg	storyboard
_	nom mas pl	storyboards
$
story-board	S.()
_	nom mas sg	story-board
_	nom mas pl	story-boards
$
storytelling	S.()
_	nom mas sg	storytelling
_	nom mas pl	storytellings
$
stot	S.()
_	nom mas sg	stot
_	nom mas pl	stots
$
stoupa	S.()
_	nom mas sg	stoupa
_	nom mas pl	stoupas
................................................................................
_	adj mas sg	surhumain
_	adj mas pl	surhumains
$
surhumanité	S.()
_	nom fem sg	surhumanité
_	nom fem pl	surhumanités
$
surhydratation	S.()
_	nom fem sg	surhydratation
_	nom fem pl	surhydratations
$
suricate	S.()
_	nom mas sg	suricate
_	nom mas pl	suricates
$
surie	F.()
_	adj fem sg	surie
_	adj fem pl	suries
................................................................................
_	nom fem sg	surjeteuse
_	nom fem pl	surjeteuses
$
surjeu	X.()
_	nom mas sg	surjeu
_	nom mas pl	surjeux
$
surjupe	S.()
_	nom fem sg	surjupe
_	nom fem pl	surjupes
$
surlargeur	S.()
_	nom fem sg	surlargeur
_	nom fem pl	surlargeurs
$
surlendemain	S.()
_	nom mas sg	surlendemain
_	nom mas pl	surlendemains
................................................................................
$
surprenante	F.()
_	adj fem sg	surprenante
_	adj fem pl	surprenantes
_	adj mas sg	surprenant
_	adj mas pl	surprenants
$
surprescription	S.()
_	nom fem sg	surprescription
_	nom fem pl	surprescriptions
$
surpresseur	S.()
_	nom mas sg	surpresseur
_	nom mas pl	surpresseurs
$
surpression	S.()
_	nom fem sg	surpression
_	nom fem pl	surpressions
................................................................................
_	nom mas sg	tâteur
_	nom mas pl	tâteurs
$
tâte-vin	S.()
_	nom mas sg	tâte-vin
_	nom mas pl	tâte-vins
$
tatie	S.()
_	nom fem sg	tatie
_	nom fem pl	taties
$
tatillonnage	S.()
_	nom mas sg	tatillonnage
_	nom mas pl	tatillonnages
$
tatillonne	F.()
_	nom adj fem sg	tatillonne
_	nom adj fem pl	tatillonnes
................................................................................
_	nom fem sg	technocratisation
_	nom fem pl	technocratisations
$
technocratisme	S.()
_	nom mas sg	technocratisme
_	nom mas pl	technocratismes
$
technoculturelle	F.()
_	adj fem sg	technoculturelle
_	adj fem pl	technoculturelles
_	adj mas sg	technoculturel
_	adj mas pl	technoculturels
$
techno-culturelle	F.()
_	adj fem sg	techno-culturelle
_	adj fem pl	techno-culturelles
_	adj mas sg	techno-culturel
_	adj mas pl	techno-culturels
$
technoéconomique	S.()
_	adj epi sg	technoéconomique
_	adj epi pl	technoéconomiques
$
techno-économique	S.()
_	adj epi sg	techno-économique
_	adj epi pl	techno-économiques
................................................................................
_	adj epi sg	télémétrique
_	adj epi pl	télémétriques
$
télencéphale	S.()
_	nom mas sg	télencéphale
_	nom mas pl	télencéphales
$
télénovela	S.()
_	nom fem sg	télénovela
_	nom fem pl	télénovelas
$
téléobjectif	S.()
_	nom mas sg	téléobjectif
_	nom mas pl	téléobjectifs
$
téléologie	S.()
_	nom fem sg	téléologie
_	nom fem pl	téléologies
................................................................................
_	nom adj fem pl	ténébreuses
_	nom adj mas inv	ténébreux
$
ténébrion	S.()
_	nom mas sg	ténébrion
_	nom mas pl	ténébrions
$
ténébrionidé	S.()
_	nom mas sg	ténébrionidé
_	nom mas pl	ténébrionidés
$
tènement	S.()
_	nom mas sg	tènement
_	nom mas pl	tènements
$
ténesme	S.()
_	nom mas sg	ténesme
_	nom mas pl	ténesmes
................................................................................
_	nom mas sg	tépidarium
_	nom mas pl	tépidariums
$
tépographie	S.()
_	nom fem sg	tépographie
_	nom fem pl	tépographies
$
teppanyaki	S.()
_	nom mas sg	teppanyaki
_	nom mas pl	teppanyakis
$
tequila	S.()
_	nom fem sg	tequila
_	nom fem pl	tequilas
$
téquila	S.()
_	nom fem sg	téquila
_	nom fem pl	téquilas
................................................................................
$
transhumante	F.()
_	nom adj fem sg	transhumante
_	nom adj fem pl	transhumantes
_	nom adj mas sg	transhumant
_	nom adj mas pl	transhumants
$
transidentitaire	S.()
_	adj epi sg	transidentitaire
_	adj epi pl	transidentitaires
$
transidentité	S.()
_	nom fem sg	transidentité
_	nom fem pl	transidentités
$
transigeance	S.()
_	nom fem sg	transigeance
_	nom fem pl	transigeances
................................................................................
_	nom mas sg	triton
_	nom mas pl	tritons
$
triturable	S.()
_	adj epi sg	triturable
_	adj epi pl	triturables
$
triturage	S.()
_	nom mas sg	triturage
_	nom mas pl	triturages
$
triturateur	S.()
_	nom mas sg	triturateur
_	nom mas pl	triturateurs
$
trituration	S.()
_	nom fem sg	trituration
_	nom fem pl	triturations
................................................................................
_	nom mas sg	troll
_	nom mas pl	trolls
$
trolle	S.()
_	nom fem sg	trolle
_	nom fem pl	trolles
$
trollesque	S.()
_	adj epi sg	trollesque
_	adj epi pl	trollesques
$
trolley	S.()
_	nom mas sg	trolley
_	nom mas pl	trolleys
$
trombe	S.()
_	nom fem sg	trombe
_	nom fem pl	trombes
................................................................................
_	nom adj epi sg	ultracolonialiste
_	nom adj epi pl	ultracolonialistes
$
ultra-colonialiste	S*()
_	nom adj epi sg	ultra-colonialiste
_	nom adj epi pl	ultra-colonialistes
$
ultraconcurrentielle	F*()
_	adj fem sg	ultraconcurrentielle
_	adj fem pl	ultraconcurrentielles
_	adj mas sg	ultraconcurrentiel
_	adj mas pl	ultraconcurrentiels
$
ultraconfidentielle	F*()
_	adj fem sg	ultraconfidentielle
_	adj fem pl	ultraconfidentielles
_	adj mas sg	ultraconfidentiel
_	adj mas pl	ultraconfidentiels
$
ultra-confidentielle	F*()
................................................................................
$
verticale	W.()
_	nom adj fem sg	verticale
_	nom adj fem pl	verticales
_	nom adj mas sg	vertical
_	nom adj mas pl	verticaux
$
verticalisateur	S.()
_	nom mas sg	verticalisateur
_	nom mas pl	verticalisateurs
$
verticalisation	S.()
_	nom fem sg	verticalisation
_	nom fem pl	verticalisations
$
verticalité	S.()
_	nom fem sg	verticalité
_	nom fem pl	verticalités
................................................................................
_	adj mas sg	victimisant
_	adj mas pl	victimisants
$
victimisation	S.()
_	nom fem sg	victimisation
_	nom fem pl	victimisations
$
victimisme	S.()
_	nom mas sg	victimisme
_	nom mas pl	victimismes
$
victimologie	S.()
_	nom fem sg	victimologie
_	nom fem pl	victimologies
$
victimologue	S.()
_	nom epi sg	victimologue
_	nom epi pl	victimologues
................................................................................
_	nom fem sg	vidéoprojection
_	nom fem pl	vidéoprojections
$
vidéoprotection	S.()
_	nom fem sg	vidéoprotection
_	nom fem pl	vidéoprotections
$
vidéo-protection	S.()
_	nom fem sg	vidéo-protection
_	nom fem pl	vidéo-protections
$
vide-ordure	S.()
_	nom mas sg	vide-ordure
_	nom mas pl	vide-ordures
$
vidéosphère	S.()
_	nom fem sg	vidéosphère
_	nom fem pl	vidéosphères
................................................................................
_	adj epi sg	vierge
_	adj epi pl	vierges
$
vierge	S.()
_	nom fem sg	vierge
_	nom fem pl	vierges
$
viétique	S.()
_	adj epi sg	viétique
_	adj epi pl	viétiques
$
vietnamienne	F.()
_	nom adj fem sg	vietnamienne
_	nom adj fem pl	vietnamiennes
_	nom adj mas sg	vietnamien
_	nom adj mas pl	vietnamiens
$
vigésimale	W.()
................................................................................
_	nom mas sg	voyer
_	nom mas pl	voyers
$
voyeurisme	S.()
_	nom mas sg	voyeurisme
_	nom mas pl	voyeurismes
$
voyeuriste	S.()
_	adj epi sg	voyeuriste
_	adj epi pl	voyeuristes
$
voyeuse	F.()
_	nom adj fem sg	voyeuse
_	nom adj fem pl	voyeuses
_	nom adj mas sg	voyeur
_	nom adj mas pl	voyeurs
$
voyou	S.()

Modified gc_lang/fr/dictionnaire/genfrdic.py from [21ee33ebdc] to [1dab8fa65c].

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
...
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
...
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
...
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
...
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
...
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
...
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
...
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
...
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
...
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
...
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
...
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
...
922
923
924
925
926
927
928



929
930
931
932
933
934


935
936
937
938
939
940
941
942
943
...
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
....
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
....
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
....
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
....
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
....
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
....
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
....
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
....
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
....
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
....
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
....
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
....
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
....
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
....
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569

import metagraphe
import metaphone2


# Dictionnaire des caractères pour le tri naturel.
# Ordre souhaitable, mais pose problème pour la recherche, car engendre des égalités de lemmes différents.
# Il faut donc travailler sur un dictionnaire trié *numériquement* et le sauvegarder selon le tri *naturel*             
CHARMAP = str.maketrans({ 'à': 'a',  'À': 'A',  'â': 'a',  'Â': 'A',  'ä': 'a',  'Ä': 'A',  'å': 'a',  'Å': 'A',  'ā': 'a',  'Ā': 'A',
                          'ç': 'c',  'Ç': 'C',
                          'é': 'e',  'É': 'E',  'è': 'e',  'È': 'E',  'ê': 'e',  'Ê': 'E',  'ë': 'e',  'Ë': 'E',  'ē': 'e',  'Ē': 'E',
                          'î': 'i',  'Î': 'I',  'ï': 'i',  'Ï': 'I',  'ī': 'i',  'Ī': 'I',
                          'ñ': 'n',
                          'ô': 'o',  'Ô': 'O',  'ö': 'o',  'Ö': 'O',  'ō': 'o',  'Ō': 'O',
                          'ù': 'u',  'Ù': 'U',  'û': 'u',  'Û': 'U',  'ü': 'u',  'Ü': 'U',  'ū': 'u',  'Ū': 'U',
................................................................................
        # Affixes
        self.sSettings = '' # enregistre tout avant la ligne # END
        self.dFlags = collections.OrderedDict()
        self.bShortenTags = False
        self.dAM = collections.OrderedDict() # étiquettes morphologiques
        self.dAF = collections.OrderedDict() # étiquettes drapeaux
        # Flexions
        self.lFlexions = []           # liste des flexions avec lemme, morphologie et occurrences 
        self.lStatsLex = []
        self.nTotOccurRecognizedWords = 0
        self.aFlexions = None
    
    def readDictionary (self, spf):
        "Lecture du dictionnaire"
        echo('Dictionnaire << [ {} ]'.format(spf), end=' ')
        for sLine in readfile(spf):
            sLine = sLine.strip()
            if not sLine.isdigit() and not sLine.startswith("#"):
                self.lEntry.append(Entree(sLine))
................................................................................
                dAF[oEntry.flags] = dAF.get(oEntry.flags, 0) + 1
            sMorph = oEntry.getMorph(nMode).strip()
            if sMorph:
                dAM[sMorph] = dAM.get(sMorph, 0) + 1

        lAF = sorted(dAF.items(), key = lambda x: (x[1], x[0]), reverse=True)
        lAM = sorted(dAM.items(), key = lambda x: (x[1], x[0]), reverse=True)
        
        with open(spDst, 'a', encoding='utf-8', newline="\n") as hDst:
            hDst.write("\n\nDrapeaux :\n")
            for nAF, elem in enumerate(lAF, 1):
                self.dAF[elem[0]] = str(nAF)
                hDst.write("  > {0[1]:>8} : {0[0]}\n".format(elem))
            hDst.write("\n\nMorphologies :\n")
            for nAM, elem in enumerate(lAM, 1):
................................................................................
                hDst.write("  > {0[1]:>8} : {0[0]}\n".format(elem))

    def writeDictionary (self, spDst, dTplVars, nMode, bSimplified):
        "Écrire le fichier dictionnaire (.dic)"
        echo(' * Dictionnaire >> [ {}.dic ] ({})'.format(dTplVars['asciiName'], dTplVars['subDicts']))
        nEntry = 0
        for oEntry in self.lEntry:
            if oEntry.di in dTplVars['subDicts']:
                nEntry += 1
        with open(spDst+'/'+dTplVars['asciiName']+'.dic', 'w', encoding='utf-8', newline="\n") as hDst:
            hDst.write(str(nEntry)+"\n")
            for oEntry in self.lEntry:
                if oEntry.di in dTplVars['subDicts']:
                    hDst.write(oEntry.getEntryLine(self, nMode, bSimplified))
    
    def writeAffixes (self, spDst, dTplVars, nMode, bSimplified):
        "Écrire le fichier des affixes (.aff)"
        echo(' * Dictionnaire >> [ {}.aff ]'.format(dTplVars['asciiName']))
        info = "# This Source Code Form is subject to the terms of the Mozilla Public\n" + \
               "# License, v. 2.0. If a copy of the MPL was not distributed with this\n" + \
               "# file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n" + \
               "# AFFIXES DU {} v{}\n".format(dTplVars['name'], self.sVersion) + \
               "# par Olivier R. -- licence MPL 2.0\n" + \
               "# Généré le " + time.strftime("%d-%m-%Y à %H:%M") + "\n" \
               "# Pour améliorer le dictionnaire, allez sur http://www.dicollecte.org/\n\n"
               
        with open(spDst+'/'+dTplVars['asciiName']+'.aff', 'w', encoding='utf-8', newline="\n") as hDst:
            hDst.write(info)
            hDst.write(self.sSettings + "\n")
            if self.bShortenTags:
                hDst.write("AM {}\n".format(len(self.dAM)))
                for item in self.dAM.items():
                    hDst.write("AM {}\n".format(item[0]))
................................................................................

    def sortEntriesNatural (self):
        echo(' * Dictionnaire - Tri naturel des entrées...')
        self.lEntry = sorted(self.lEntry, key=Entree.keyTriNat)

    def sortEntriesNumerical (self):
        echo(' * Dictionnaire - Tri numérique des entrées...')
        self.lEntry = sorted(self.lEntry, key=Entree.keyTriNum)        

    def sortLexiconByFlexion (self):
        echo(' * Dictionnaire - tri du lexique (par flexion)...')
        self.lFlexions = sorted(self.lFlexions, key=Flexion.keyFlexion)

    def sortLexiconByFreq (self):
        echo(' * Dictionnaire - tri du lexique (par fréquence)...')
................................................................................
                d[oFlex.sFlexion] = [oFlex.oEntry]
        for oFlex in self.lFlexions:
            oFlex.lMulti = list(d[oFlex.sFlexion])
            oFlex.nMulti = len(oFlex.lMulti)
        for oFlex in self.lFlexions:
            oFlex.lMulti.remove(oFlex.oEntry)
            oFlex.nMulti -= 1
        
    def setTagsFrom (self, other):
        echo(' * Dictionnaire - copie des tags...')
        for i in range(self.nEntry):
            for oEntry in other.lEntry:
                if self.lEntry[i].lemma == oEntry.lemma and self.lEntry[i].flags == oEntry.flags:
                    self.lEntry[i].setTagsFrom(oEntry)

................................................................................
            hDst.write(oStatsLex.getInfo())
            for oFlex in self.lFlexions:
                oFlex.setOccur(oStatsLex.getFlexionOccur(oFlex.sFlexion))
            self.nTotOccurRecognizedWords = 0
            for oFlex in self.lFlexions:
                oFlex.calcOccur()
                self.nTotOccurRecognizedWords += oFlex.nOccur
            
            # Report des occurrences
            echo("   report des occurrences des formes fléchies multiples...")
            hDst.write("Report des occurrences des formes fléchies multiples :\n")
            hDst.write("  Légende :\n")
            hDst.write("    >>   le nombre d’occurrences de la flexion est ramené à la moyenne.\n")
            hDst.write("    +>   le nombre d’occurrences de la flexion est augmenté avec le surplus d’occurrences des flexions ramenées à la moyenne.\n")
            hDst.write("    %>   le nombre d’occurrences de la flexion est pondéré avec le poids de la moyenne de l’entrée.\n\n")

            for oEntry in self.lEntry:
                oEntry.calcOccurFromFlexions()
                oEntry.calcAverageKnownOccurrence()
                oEntry.solveOccurMultipleFlexions(hDst, oStatsLex)
                oEntry.calcOccurFromFlexions()
            
            # Fréquences
            echo("   calcul des fréquences et indices de fréquence...")
            for oFlex in self.lFlexions:
                oFlex.calcFreq(self.nTotOccurRecognizedWords)
            for oEntry in self.lEntry:
                oEntry.calcFreq(self.nTotOccurRecognizedWords)
            
            # Entrées, statistiques
            echo("   statistiques...")
            hDst.write("\n\nNatures grammaticales :\n")
            d = {}
            for oEntry in self.lEntry:
                po = re.sub("(?<=v[0-3])[itnpqrmaezx_]+", "", oEntry.po)
                d[po] = d.get(po, 0) + 1
            for e in sorted(d.items(), key = lambda x: (x[1], x[0]), reverse=True):
                hDst.write(" * {0[1]:<15} : {0[0]}\n".format(e))
            
            hDst.write("\n\nVentilation des entrées par indice de fréquence :\n")
            d1 = {}
            d2 = {}
            for oEntry in self.lEntry:
                d1[oEntry.fq] = d1.get(oEntry.fq, 0) + 1
                d2[oEntry.fq] = d2.get(oEntry.fq, 0) + oEntry.fFreq
            for k in sorted(d1.keys()):
                hDst.write(" * {} : {} entrées ({:.2f} %)  → {:.9f} %\n".format(k, d1[k], (d1[k]*100)/self.nEntry, d2[k]))
                    
            hDst.write("\n\nRépartition des entrées par sous-dictionnaire :\n")
            d = {}
            for oEntry in self.lEntry:
                d[oEntry.di] = d.get(oEntry.di, 0) + 1
            for sKey, nVal in d.items():
                hDst.write(" * {0:<15} : {1} entrées ({2:.2f} %)\n".format(dSUBDIC[sKey], nVal, (nVal*100)/self.nEntry))
            
            # Occurrences des lettres
            echo("   occurrences des lettres...")
            d = {}
            for oFlex in self.lFlexions:
                for c in oFlex.sFlexion:
                    d[c] = d.get(c, 0) + oFlex.nOccur
            nTot = 0
................................................................................
            hDst.write("\n\nNombre de formes fléchies : {}\n".format(len(self.lFlexions)))
            hDst.write("\n\nNombre de graphies : {}\n".format(len(self.aFlexions)))

    def calcMetagraphe (self):
        echo(" * Lexique - Metagraphe")
        for oFlex in self.lFlexions:
            oFlex.calcMetagraphe()
    
    def calcMetaphone2 (self):
        echo(" * Lexique - Metaphone 2")
        for oFlex in self.lFlexions:
            oFlex.calcMetaphone2()
    
    def createNgrams (self, spDest, n):
        echo(" * Lexique - Ngrams " + str(n))
        if n < 2:
            echo("erreur: n = " + str(n))
            return
        dOccur = {} # ngram:n
        dRefW = {} # ngram:set(idx)
................................................................................
        file_util.copy_file('_templates/ooo/french_flag.png', spExt)
        file_util.copy_file('_templates/ooo/french_flag_16.bmp', spExt+'/ui')
        copyTemplate('_templates/ooo', spExt, 'description.xml', dTplVars)
        copyTemplate('_templates/ooo', spExt, 'dictionaries.xcu', dTplVars)
        #file_util.copy_file('_templates/ooo/dictionaries.xcu.tpl.xml', spExt)
        copyTemplate('_templates/ooo', spExt, 'package-description.txt', dTplVars)
        for dVars in lDictVars:
            dicPath = spBuild + '/' + PREFIX_DICT_PATH + self.sVersion 
            file_util.copy_file(dicPath+'/'+dVars['asciiName']+'.dic', spExt+'/dictionaries/'+dVars['asciiName']+'.dic')
            file_util.copy_file(dicPath+'/'+dVars['asciiName']+'.aff', spExt+'/dictionaries/'+dVars['asciiName']+'.aff')
        copyTemplate('orthographe', spExt+'/dictionaries', 'README_dict_fr.txt', dTplVars)
        # thesaurus
        file_util.copy_file('thesaurus/thes_fr.dat', spExt+'/dictionaries')
        file_util.copy_file('thesaurus/thes_fr.idx', spExt+'/dictionaries')
        file_util.copy_file('thesaurus/README_thes_fr.txt', spExt+'/dictionaries')
................................................................................
        file_util.copy_file('césures/README_hyph_fr-2.9.txt', spExt+'/dictionaries')
        # zip
        createZipFiles(spExt, spBuild, sExtensionName + '.oxt')
        # copy to Grammalecte Project
        if spDestGL:
            echo("   extension copiée dans Grammalecte...")
            dir_util.copy_tree(spExt+'/dictionaries', spDestGL)
    
    def createMozillaExtensions (self, spBuild, dTplVars, lDictVars, spDestGL=""):
        # Mozilla extension 1
        echo(" * Dictionnaire >> extension pour Mozilla")
        dTplVars['version'] = self.sVersion
        sExtensionName = EXT_PREFIX_MOZ + self.sVersion
        spExt = spBuild + '/' + sExtensionName
        dir_util.mkpath(spExt+'/dictionaries')
................................................................................
        createZipFiles(spExt, spBuild, sExtensionName + '.xpi')
        # Grammalecte
        if spDestGL:
            echo(" * Dictionnaire >> copie des dicos dans Grammalecte")
            for dVars in lDictVars:
                file_util.copy_file(spDict+'/'+dVars['asciiName']+'.dic', spDestGL+'/'+dVars['mozAsciiName']+"/"+dVars['mozAsciiName']+'.dic')
                file_util.copy_file(spDict+'/'+dVars['asciiName']+'.aff', spDestGL+'/'+dVars['mozAsciiName']+"/"+dVars['mozAsciiName']+'.aff')
    
    def createFileIfqForDB (self, spBuild):
        echo(" * Dictionnaire >> indices de fréquence pour la DB...")
        with open(spBuild+'/dictIdxIfq-'+self.sVersion+'.diff.txt', 'w', encoding='utf-8', newline="\n") as hDiff, \
             open(spBuild+'/dictIdxIfq-'+self.sVersion+'.notes.txt', 'w', encoding='utf-8', newline="\n") as hNotes:
            for oEntry in self.lEntry:
                if oEntry.fq != oEntry.oldFq:
                    hDiff.write("{0.iD}\t{0.fq}\n".format(oEntry))
                    hNotes.write("{0.lemma}/{0.flags}\t{0.oldFq} > {0.fq}\n".format(oEntry))
        
    def createLexiconPackages (self, spBuild, version, oStatsLex, spDestGL=""):
        sLexName = LEX_PREFIX + version
        spLex = spBuild + '/' + sLexName
        dir_util.mkpath(spLex)
        # write Dicollecte lexicon
        self.sortLexiconByFreq()
        self.writeLexicon(spLex + '/' + sLexName + '.txt', version, oStatsLex)
................................................................................
        self.iD = '0'

        # autres
        self.comment = ''
        self.err = ''
        self.nFlexions = 0
        self.lFlexions = []
        self.sRadical = ''
        self.nOccur = 0
        self.nAKO = -1   # Average known occurrences
        self.fFreq = 0
        self.oldFq = ''
        
        sLine = sLine.rstrip(" \n")
        # commentaire
        if '#' in sLine:
            sLine, comment = sLine.split('#', 1)
            self.comment = comment.strip()
        # éléments de la ligne
        elems = sLine.split()
        nElems = len(elems)
        # lemme et drapeaux
        firstElems = elems[0].split('/')
        self.lemma = firstElems[0]
        self.flags = firstElems[1]  if len(firstElems) > 1  else ''
        # morph
        for i in range(1, nElems):
................................................................................
                else:
                    echo('  ## Champ inconnu: {}  dans  {}/{}'.format(fields[0], self.lemma, self.flags))
            else:
                self.err = self.err + elems[i]
        if self.err:
            echo("\n## Erreur dans le dictionnaire : {}".format(self.err))
            echo("   dans : " + self.lemma)
                
    def __str__ (self):
        return "{0.lemma}/{0.flags} {1}".format(self, self.getMorph(2))

    def check (self):
        sErr = ''
        if self.lemma == '':
            sErr += 'lemme vide'
................................................................................
        if re.search(r"\s$", self.lemma):
            sErr += 'espace en fin de lemme'
        if re.match(r"v[0123]", self.po) and not re.match(r"[eas_][ix_][tx_][nx_][pqreuvx_][mx_][ex_z][ax_z]\b", self.po[2:]):
            sErr += 'verbe inconnu: ' + self.po
        if (re.match(r"S[*.]", self.flags) and re.search("[sxz]$", self.lemma)) or (re.match(r"X[*.]", self.flags) and not re.search("[ul]$", self.lemma)):
            sErr += 'drapeau inutile'
        if self.iz == '' and re.match(r"[SXAI](?!=)", self.flags) and self.po:
            sErr += '[is]'
        if re.match(r"pl|sg|inv", self.iz):
            sErr += '[is]'
        if re.match(r"[FW]", self.flags) and re.search(r"epi|mas|fem|inv|sg|pl", self.iz):
            sErr += '[is]'
        if re.match(r"[FW]", self.flags) and re.search(r"[^eë]$", self.lemma):
            sErr += "fin de lemme inapproprié"
        if re.match(r".\*", self.flags) and re.match(r"[bcdfgjklmnpqrstvwxz]", self.lemma):
            sErr += 'drapeau pour lemme commençant par une voyelle'
        if re.search(r"pl|sg|inv", self.iz) and re.match(r"[SXAIFW](?!=)", self.flags):
            sErr += '[is]'
        if re.search(r"nom|adj", self.po) and re.match(r"(?i)[aâàäáeéèêëiîïíìoôöóòuûüúù]", self.lemma) and re.match("[SFWXAI][.]", self.flags) \
           and "pel" not in self.lx:
            sErr += 'le drapeau derait finir avec *'
        if not self.flags and self.iz.endswith(("mas", "fem", "epi")):
            sErr += '[is] incomplet'
        if self.flags.startswith(("a", "b", "c", "d")) and not self.lemma.endswith("er"):
            sErr += "drapeau pour verbe du 1ᵉʳ groupe sur un lemme non conforme"
................................................................................

    def keyTriNat (self):
        return (self.lemma.translate(CHARMAP), self.flags, self.po)

    def keyTriNum (self):
        return (self.lemma, self.flags, self.po)

    def getEntryLine (self, oDict, nMode, bSimplified=False):    
        sLine = self.lemma
        if self.flags:
            sLine += '/'
            sLine += self.flags  if not oDict.bShortenTags or bSimplified  else oDict.dAF[self.flags]
        if bSimplified:
            return sLine.replace("()", "") + "\n"
        if nMode > 0:
            sMorph = self.getMorph(nMode)
................................................................................
                if not sMorph.endswith((" mas", " fem", " epi")):
                    self.lFlexions.append( Flexion(self, sFlex, sMorph, sDic) )
                    self.nFlexions += 1
                else:
                    #echo(sFlex + " " + sMorph + ", ")
                    pass
        # Drapeaux dont le lemme féminin doit être remplacé par le masculin dans la gestion des formes fléchies



        if self.flags.startswith(("F.", "F*", "W.", "W*")):
            # recherche de la forme masculine
            for t in lTuples:
                sMorph = self.clean(t[1])
                if sMorph.endswith('mas') or sMorph.endswith('mas sg') or sMorph.endswith('mas inv'): 
                    self.sRadical = t[0]


        else:
            self.sRadical = self.lemma
        # Tag duplicates
        d = {}
        for oFlex in self.lFlexions:
            d[oFlex.sFlexion] = d.get(oFlex.sFlexion, 0) + 1
        for oFlex in self.lFlexions:
            oFlex.nDup = d[oFlex.sFlexion]

................................................................................
                                        lFlexions.append( (oRule.add+flex[0], flex[1]+ruleMorph) )
                                else:
                                    lFlexions.append(flexion)
                            else:
                                flexion = (self.lemma.replace(oRule.cut, oRule.add, 1), ruleMorph+morph, oRule.di)
                                if oFlag.bMix:
                                    lFlexPrefix.append(flexion)
                                    for flex in lFlexSuffix: 
                                        lFlexions.append( (flex[0].replace(oRule.cut, oRule.add, 1), flex[1]+ruleMorph) )
                                else:
                                    lFlexions.append(flexion)
                            if oRule.flags != '' and oRule.flags != '**':
                                lFlexions.extend(Entree(flexion[0]+'/'+oRule.flags)._flechir(dFlags, flexion[1], iPR+1))
                else:
                    # cas des suffixes
................................................................................
    def calcOccurFromFlexions (self):
        self.nOccur = 0
        for o in self.lFlexions:
            self.nOccur += o.nOccur

    def calcAverageKnownOccurrence (self):
        # nous calculons la moyenne des occurrences des formes fléchies
        # qui n’ont pas d’équivalent dans les autres entrées (nMulti = 0) 
        nOccur = 0
        nFlex = 0
        for oFlex in self.lFlexions:
            if oFlex.nMulti == 0:
                nOccur += oFlex.nOccur
                nFlex += 1
        # moyenne des formes fléchies sans équivalent ou -1
        self.nAKO = math.ceil(nOccur / nFlex)  if nFlex > 0  else -1
    
    def solveOccurMultipleFlexions (self, hDst, oStatsLex):
        sBlank = "           "
        if self.nAKO >= 0:
            for oFlex in self.lFlexions:
                if oFlex.nMulti > 0 and not oFlex.bBlocked:
                    # on trie les entrées avec AKO et sans AKO
                    lEntWithAKO = []
                    lEntNoAKO = []
                    for oEntry in oFlex.lMulti:
                        if oEntry.nAKO >= 0:
                            lEntWithAKO.append(oEntry)
                        else:
                            lEntNoAKO.append(oEntry)
                    
                    if lEntNoAKO:
                        # on calcule la différence totale occasionnée par du passage des flexions appartenant à des entrées avec AKO au niveau AKO
                        nDiff = (oFlex.nOccur - self.nAKO) * oFlex.nDup
                        for oEntry in lEntWithAKO:
                            for oFlexM in oEntry.lFlexions:
                                if oFlex.sFlexion == oFlexM.sFlexion:
                                    nDiff += oFlexM.nOccur - oEntry.nAKO
................................................................................
                                        oFlexM.setOccurAndBlock(nNewOccur)
                    else:
                        # Toutes les entrées sont avec AKO : on pondère
                        nFlexOccur = oStatsLex.getFlexionOccur(oFlex.sFlexion)
                        nTotAKO = self.nAKO
                        for oEnt in oFlex.lMulti:
                            nTotAKO += oEnt.nAKO
                        
                        hDst.write(" = {0.sFlexion}\n".format(oFlex))
                        hDst.write("       moyennes connues\n")
                        for oFlexD in self.lFlexions:
                            if oFlex.sFlexion == oFlexD.sFlexion:
                                nNewOccur = math.ceil((nFlexOccur * (self.nAKO / nTotAKO)) / oFlexD.nDup)  if nTotAKO  else 0
                                hDst.write(sBlank + "{2:<30} {0.sMorph:<30}  {0.nOccur:>10}  %> {1:>10}\n".format(oFlexD, nNewOccur, self.getShortDescr()))
                                oFlexD.setOccurAndBlock(nNewOccur)
                        for oEntry in oFlex.lMulti:
                            for oFlexM in oEntry.lFlexions:
                                if oFlex.sFlexion == oFlexM.sFlexion:
                                    nNewOccur = math.ceil((nFlexOccur * (oEntry.nAKO / nTotAKO)) / oFlexM.nDup)  if nTotAKO  else 0
                                    hDst.write(sBlank + "{2:<30} {0.sMorph:<30}  {0.nOccur:>10}  %> {1:>10}\n".format(oFlexM, nNewOccur, oEntry.getShortDescr()))
                                    oFlexM.setOccurAndBlock(nNewOccur)
        
    def calcFreq (self, nTot):
        self.fFreq = (self.nOccur * 100) / nTot
        self.oldFq = self.fq
        self.fq = getIfq(self.fFreq)



................................................................................
        self.nDup    = 0    # duplicates in the same entry
        self.nMulti  = 0    # duplicates with other entries
        self.lMulti  = []   # list of similar flexions
        self.fFreq   = 0
        self.cFq     = ''
        self.metagfx = ''   # métagraphe
        self.metaph2 = ''   # métaphone 2
    
    def setOccur (self, n):
        self.nOccur = n

    def setOccurAndBlock (self, n):
        self.nOccur = n
        self.bBlocked = True

    def calcOccur (self):
        self.nOccur = math.ceil((self.nOccur / (self.nMulti+1)) / self.nDup)
    
    def calcFreq (self, nTot):
        self.fFreq = (self.nOccur * 100) / nTot
        self.cFq = getIfq(self.fFreq)
    
    def calcMetagraphe (self):
        t = metagraphe.getMetagraphe(self.sFlexion, self.sMorph)
        self.metagfx = t[0]  if not t[1]  else t[0]+"/"+t[1]

    def calcMetaphone2 (self):
        t = metaphone2.dm(self.sFlexion)
        self.metaph2 = t[0]  if not t[1]  else t[0]+"/"+t[1]
................................................................................
            sOccurs += t[1] + "\t"
        return "id\tFlexion\tLemme\tÉtiquettes\tMétagraphe (β)\tMetaphone2\tNotes\tSémantique\tÉtymologie\tSous-dictionnaire\t" + sOccurs + "Total occurrences\tDoublons\tMultiples\tFréquence\tIndice de fréquence\n"

    def __str__ (self, oStatsLex):
        sOccurs = ''
        for v in oStatsLex.dFlexions[self.sFlexion]:
            sOccurs += str(v) + "\t"
        return "{0.oEntry.iD}\t{0.sFlexion}\t{0.oEntry.sRadical}\t{0.sMorph}\t{0.metagfx}\t{0.metaph2}\t{0.oEntry.lx}\t{0.oEntry.se}\t{0.oEntry.et}\t{0.oEntry.di}{2}\t{1}{0.nOccur}\t{0.nDup}\t{0.nMulti}\t{0.fFreq:.15f}\t{0.cFq}\n".format(self, sOccurs, "/"+self.cDic if self.cDic != "*" else "")

    @classmethod
    def simpleHeader (cls):
        return "# :POS ;LEX ~SEM =FQ /DIC\n"

    def getGrammarCheckerRepr (self):
        return "{0.sFlexion}\t{0.oEntry.lemma}\t{1}\n".format(self, self._getSimpleTags())
................................................................................
        "ipre": ":Ip", "iimp": ":Iq", "ipsi": ":Is", "ifut": ":If",
        "spre": ":Sp", "simp": ":Sq", "cond": ":K", "impe": ":E",
        "1sg": ":1s", "1isg": ":1ś", "1jsg": ":1ŝ", "2sg": ":2s", "3sg": ":3s", "1pl": ":1p", "2pl": ":2p", "3pl": ":3p", "3pl!": ":3p!",
        "prepv": ":Rv", "prep": ":R", "loc.prep": ":Ŕ",
        "detpos": ":Dp", "detdem": ":Dd", "detind": ":Di", "detneg": ":Dn", "detex": ":De", "det": ":D",
        "advint": ":U",
        "prodem": ":Od", "proind": ":Oi", "proint": ":Ot", "proneg": ":On", "prorel": ":Or", "proadv": ":Ow",
        "properobj": ":Oo", "propersuj": ":Os", "1pe": ":O1", "2pe": ":O2", "3pe": ":O3",
        "cjco": ":Cc", "cjsub": ":Cs", "cj": ":C", "loc.cj": ":Ĉ", "loc.cjsub": ":Ĉs",
        "prn": ":M1", "patr": ":M2", "loc.patr": ":Ḿ2", "npr": ":MP", "nompr": ":NM",
        "pfx": ":Zp", "sfx": ":Zs",
        "div": ":H",
        "err": ":#",
        # LEX
        "symb": ";S"
................................................................................
            s += "/" + self.oEntry.di
        return s

    def keyTriNat (self):
        return (self.sFlexion.translate(CHARMAP), self.sMorph)

    def keyFreq (self):
        return (100-self.fFreq, self.oEntry.sRadical, self.sFlexion)

    def keyOcc (self):
        return (self.nOccur, self.oEntry.sRadical, self.sFlexion)
        
    def keyIdx (self):
        return self.oEntry.iD

    def keyFlexion (self):
        return self.sFlexion


................................................................................
    def __init__ (self, sFlagType, sFlagName, sMix):
        self.sFlagName = sFlagName
        self.bSfx = True  if sFlagType == 'SFX'  else False
        self.bMix = True  if sMix == 'Y'  else False
        self.lRules = []
        self.nRules = 0
        self.nOccur = 0
        
    def addAffixRule (self, line):
        "ajoute une règle au drapeau"
        oRule = AffixRule(line)
        self.lRules.append(oRule)
        self.nRules += 1

    def getFlag (self, subDicts, oDict, nMode, bSimplified):
................................................................................
        # champs de Dicollecte
        self.lx = ''
        self.di = '*'
        # erreurs
        self.err = ''
        # autres champs
        self.nOccur = 0
        
        sLine = sLine.rstrip(" \n")
        # commentaire
        if '#' in sLine:
            sLine, comment = sLine.split('#', 1)
            self.comment = comment.strip()
        # éléments de la ligne
        elems = sLine.split()
................................................................................
                    self.lx = fields[1]  if self.lx == ''  else self.lx + ' ' + fields[1]
                elif fields[0] == 'di':
                    self.di = fields[1]
                else:
                    echo('Champ inconnu: {}  dans  {}'.format(fields[0], self.sFlagName))
            else:
                echo("  # Erreur affixe : {}".format(line))
    
    def isReplicationRule (self):
        "is this rule used for replication of a virtual lemma"
        return self.flags == "" and ((self.cut == "0" and self.add == "") or self.cut == self.add)

    def getRuleLine (self, oDict, nMode, bSimplified=False):
        sLine = 'SFX'  if self.bSfx  else 'PFX'
        sLine += ' ' + self.sFlagName + ' ' + self.cut + ' '
................................................................................
                sLine = sLine.replace("()", "")
        sLine += ' ' + self.cond
        if not bSimplified and nMode > 0:
            sMorph = self.getMorph(nMode)
            if sMorph:
                sLine += sMorph  if not oDict.bShortenTags or bSimplified  else ' ' + oDict.dAM[sMorph.strip()]
        return sLine + "\n"
    
    def getMorph (self, nMode):
        # morphology for Hunspell
        txt = ''
        if self.po: txt += fieldToHunspell('po', self.po)
        if self.iz: txt += fieldToHunspell('is', self.iz)
        if self.ds: txt += fieldToHunspell('ds', self.ds)
        if self.ts: txt += fieldToHunspell('ts', self.ts)
................................................................................


class StatsLex:
    def __init__ (self, oDict):
        echo("Lexique statistique")
        self.dFlexions = { oFlex.sFlexion: []  for oFlex in oDict.lFlexions }
        self.lLex = []
        
    def addLexFromFile (self, sPathFile, cLexID, sLexName):
        if not os.path.isfile(sPathFile):
            echo(' * Lexique statistique - fichier {} introuvable'.format(sPathFile))
            return None
        if len(cLexID) != 1:
            echo(' * Lexique statistique - fichier {} - identifiant incorrect, 1 caractère requis'.format(sPathFile))
            return None
................................................................................
                hDst.write(str(t)+"\n")
            for e in self.dFlexions.items():
                hDst.write("{} - {}\n".format(e[0], e[1]))



def main ():

    xParser = argparse.ArgumentParser()
    xParser.add_argument("-v", "--verdic", help="set dictionary version, i.e. 5.4", type=str, default="X.Y.z")
    xParser.add_argument("-m", "--mode", help="0: no tags,  1: Hunspell tags (default),  2: All tags", type=int, choices=[0, 1, 2], default=1)
    xParser.add_argument("-u", "--uncompress", help="do not use Hunspell compression", action="store_true")
    xParser.add_argument("-s", "--simplify", help="no virtual lemmas", action="store_true")
    xParser.add_argument("-sv", "--spellvariants", help="generate spell variants", action="store_true")
    xParser.add_argument("-gl", "--grammalecte", help="copy generated files to Grammalecte folders", action="store_true")
................................................................................
        xArgs.uncompress = True

    echo("Python: " + sys.version)
    echo("Version: " + xArgs.verdic)
    echo("Simplify: " + str(xArgs.simplify))
    echo("Mode: " + str(xArgs.mode))
    echo("Compression: " + str(not(xArgs.uncompress)))
    
    ### création du répertoire
    spBuild = BUILD_PATH + '/' + xArgs.verdic
    dir_util.mkpath(spBuild)
    
    ### Lecture des fichiers et création du dictionnaire
    oFrenchDict = Dictionnaire(xArgs.verdic, "French dictionary")
    for sFile in ['orthographe/FRANCAIS.dic']:
        oFrenchDict.readDictionary(sFile)
    oFrenchDict.readAffixes('orthographe/FRANCAIS_5.aff')
    
    ### Contrôle
    oFrenchDict.sortEntriesNatural()
    oFrenchDict.checkEntries()
    
    ### Lexique
    oFrenchDict.generateFlexions()
    oFrenchDict.calcMetagraphe()
    oFrenchDict.calcMetaphone2()

    #oFrenchDict.createNgrams(spBuild, 3)
    if xArgs.spellvariants:
................................................................................
    oStatsLex = StatsLex(oFrenchDict)
    oStatsLex.addLexFromFile('lexique/corpus_data/stats_google_ngram_1.txt', 'G', 'Google 1-grams')
    oStatsLex.addLexFromFile('lexique/corpus_data/stats_frwiki.txt', 'W', 'Wikipédia')
    oStatsLex.addLexFromFile('lexique/corpus_data/stats_frwikisource.txt', 'S', 'Wikisource')
    oStatsLex.addLexFromFile('lexique/corpus_data/stats_litterature.txt', 'L', 'Littérature')
    oStatsLex.write(spBuild+'/test_lex.txt')
    oFrenchDict.calculateStats(oStatsLex, spfStats)
    
    ### écriture des paquets
    echo("Création des paquets...")

    spLexiconDestGL = "../../../lexicons"  if xArgs.grammalecte  else ""
    spLibreOfficeExtDestGL = "../oxt/Dictionnaires/dictionaries"  if xArgs.grammalecte  else ""
    spMozillaExtDestGL = "../xpi/data/dictionaries"  if xArgs.grammalecte  else ""
    spDataDestGL = "../data"  if xArgs.grammalecte  else ""

    if not xArgs.uncompress:
        oFrenchDict.defineAbreviatedTags(xArgs.mode, spfStats)
    oFrenchDict.createFiles(spBuild, [dMODERNE, dTOUTESVAR, dCLASSIQUE, dREFORME1990], xArgs.mode, xArgs.simplify)
    oFrenchDict.createLexiconPackages(spBuild, xArgs.verdic, oStatsLex, spLexiconDestGL)
    oFrenchDict.createFileIfqForDB(spBuild)







|







 







|



|







 







|







 







|




|
|
|










|







 







|







 







|







 







|













|






|









|








|






|







 







|




|







 







|







 







|







 







|








|







 







|




|






|







 







|







 







|

|

|





|







 







|
|







 







>
>
>
|
|
|
|
<
<
>
>
|
|







 







|







 







|








|













|







 







|













|







 







|









|



|







 







|







 







|







 







|


|
|







 







|







 







|







 







|







 







|







 







|







 







<







 







|



|





|



|







 







|





|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
...
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
...
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
...
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
...
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
...
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
...
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
...
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
...
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
...
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
...
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
...
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
...
922
923
924
925
926
927
928
929
930
931
932
933
934
935


936
937
938
939
940
941
942
943
944
945
946
...
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
....
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
....
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
....
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
....
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
....
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
....
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
....
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
....
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
....
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
....
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
....
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
....
1500
1501
1502
1503
1504
1505
1506

1507
1508
1509
1510
1511
1512
1513
....
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
....
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571

import metagraphe
import metaphone2


# Dictionnaire des caractères pour le tri naturel.
# Ordre souhaitable, mais pose problème pour la recherche, car engendre des égalités de lemmes différents.
# Il faut donc travailler sur un dictionnaire trié *numériquement* et le sauvegarder selon le tri *naturel*
CHARMAP = str.maketrans({ 'à': 'a',  'À': 'A',  'â': 'a',  'Â': 'A',  'ä': 'a',  'Ä': 'A',  'å': 'a',  'Å': 'A',  'ā': 'a',  'Ā': 'A',
                          'ç': 'c',  'Ç': 'C',
                          'é': 'e',  'É': 'E',  'è': 'e',  'È': 'E',  'ê': 'e',  'Ê': 'E',  'ë': 'e',  'Ë': 'E',  'ē': 'e',  'Ē': 'E',
                          'î': 'i',  'Î': 'I',  'ï': 'i',  'Ï': 'I',  'ī': 'i',  'Ī': 'I',
                          'ñ': 'n',
                          'ô': 'o',  'Ô': 'O',  'ö': 'o',  'Ö': 'O',  'ō': 'o',  'Ō': 'O',
                          'ù': 'u',  'Ù': 'U',  'û': 'u',  'Û': 'U',  'ü': 'u',  'Ü': 'U',  'ū': 'u',  'Ū': 'U',
................................................................................
        # Affixes
        self.sSettings = '' # enregistre tout avant la ligne # END
        self.dFlags = collections.OrderedDict()
        self.bShortenTags = False
        self.dAM = collections.OrderedDict() # étiquettes morphologiques
        self.dAF = collections.OrderedDict() # étiquettes drapeaux
        # Flexions
        self.lFlexions = []           # liste des flexions avec lemme, morphologie et occurrences
        self.lStatsLex = []
        self.nTotOccurRecognizedWords = 0
        self.aFlexions = None

    def readDictionary (self, spf):
        "Lecture du dictionnaire"
        echo('Dictionnaire << [ {} ]'.format(spf), end=' ')
        for sLine in readfile(spf):
            sLine = sLine.strip()
            if not sLine.isdigit() and not sLine.startswith("#"):
                self.lEntry.append(Entree(sLine))
................................................................................
                dAF[oEntry.flags] = dAF.get(oEntry.flags, 0) + 1
            sMorph = oEntry.getMorph(nMode).strip()
            if sMorph:
                dAM[sMorph] = dAM.get(sMorph, 0) + 1

        lAF = sorted(dAF.items(), key = lambda x: (x[1], x[0]), reverse=True)
        lAM = sorted(dAM.items(), key = lambda x: (x[1], x[0]), reverse=True)

        with open(spDst, 'a', encoding='utf-8', newline="\n") as hDst:
            hDst.write("\n\nDrapeaux :\n")
            for nAF, elem in enumerate(lAF, 1):
                self.dAF[elem[0]] = str(nAF)
                hDst.write("  > {0[1]:>8} : {0[0]}\n".format(elem))
            hDst.write("\n\nMorphologies :\n")
            for nAM, elem in enumerate(lAM, 1):
................................................................................
                hDst.write("  > {0[1]:>8} : {0[0]}\n".format(elem))

    def writeDictionary (self, spDst, dTplVars, nMode, bSimplified):
        "Écrire le fichier dictionnaire (.dic)"
        echo(' * Dictionnaire >> [ {}.dic ] ({})'.format(dTplVars['asciiName'], dTplVars['subDicts']))
        nEntry = 0
        for oEntry in self.lEntry:
            if oEntry.di in dTplVars['subDicts'] and " " not in oEntry.lemma:
                nEntry += 1
        with open(spDst+'/'+dTplVars['asciiName']+'.dic', 'w', encoding='utf-8', newline="\n") as hDst:
            hDst.write(str(nEntry)+"\n")
            for oEntry in self.lEntry:
                if oEntry.di in dTplVars['subDicts'] and " " not in oEntry.lemma:
                    hDst.write(oEntry.getHunspellLine(self, nMode, bSimplified))

    def writeAffixes (self, spDst, dTplVars, nMode, bSimplified):
        "Écrire le fichier des affixes (.aff)"
        echo(' * Dictionnaire >> [ {}.aff ]'.format(dTplVars['asciiName']))
        info = "# This Source Code Form is subject to the terms of the Mozilla Public\n" + \
               "# License, v. 2.0. If a copy of the MPL was not distributed with this\n" + \
               "# file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n" + \
               "# AFFIXES DU {} v{}\n".format(dTplVars['name'], self.sVersion) + \
               "# par Olivier R. -- licence MPL 2.0\n" + \
               "# Généré le " + time.strftime("%d-%m-%Y à %H:%M") + "\n" \
               "# Pour améliorer le dictionnaire, allez sur http://www.dicollecte.org/\n\n"

        with open(spDst+'/'+dTplVars['asciiName']+'.aff', 'w', encoding='utf-8', newline="\n") as hDst:
            hDst.write(info)
            hDst.write(self.sSettings + "\n")
            if self.bShortenTags:
                hDst.write("AM {}\n".format(len(self.dAM)))
                for item in self.dAM.items():
                    hDst.write("AM {}\n".format(item[0]))
................................................................................

    def sortEntriesNatural (self):
        echo(' * Dictionnaire - Tri naturel des entrées...')
        self.lEntry = sorted(self.lEntry, key=Entree.keyTriNat)

    def sortEntriesNumerical (self):
        echo(' * Dictionnaire - Tri numérique des entrées...')
        self.lEntry = sorted(self.lEntry, key=Entree.keyTriNum)

    def sortLexiconByFlexion (self):
        echo(' * Dictionnaire - tri du lexique (par flexion)...')
        self.lFlexions = sorted(self.lFlexions, key=Flexion.keyFlexion)

    def sortLexiconByFreq (self):
        echo(' * Dictionnaire - tri du lexique (par fréquence)...')
................................................................................
                d[oFlex.sFlexion] = [oFlex.oEntry]
        for oFlex in self.lFlexions:
            oFlex.lMulti = list(d[oFlex.sFlexion])
            oFlex.nMulti = len(oFlex.lMulti)
        for oFlex in self.lFlexions:
            oFlex.lMulti.remove(oFlex.oEntry)
            oFlex.nMulti -= 1

    def setTagsFrom (self, other):
        echo(' * Dictionnaire - copie des tags...')
        for i in range(self.nEntry):
            for oEntry in other.lEntry:
                if self.lEntry[i].lemma == oEntry.lemma and self.lEntry[i].flags == oEntry.flags:
                    self.lEntry[i].setTagsFrom(oEntry)

................................................................................
            hDst.write(oStatsLex.getInfo())
            for oFlex in self.lFlexions:
                oFlex.setOccur(oStatsLex.getFlexionOccur(oFlex.sFlexion))
            self.nTotOccurRecognizedWords = 0
            for oFlex in self.lFlexions:
                oFlex.calcOccur()
                self.nTotOccurRecognizedWords += oFlex.nOccur

            # Report des occurrences
            echo("   report des occurrences des formes fléchies multiples...")
            hDst.write("Report des occurrences des formes fléchies multiples :\n")
            hDst.write("  Légende :\n")
            hDst.write("    >>   le nombre d’occurrences de la flexion est ramené à la moyenne.\n")
            hDst.write("    +>   le nombre d’occurrences de la flexion est augmenté avec le surplus d’occurrences des flexions ramenées à la moyenne.\n")
            hDst.write("    %>   le nombre d’occurrences de la flexion est pondéré avec le poids de la moyenne de l’entrée.\n\n")

            for oEntry in self.lEntry:
                oEntry.calcOccurFromFlexions()
                oEntry.calcAverageKnownOccurrence()
                oEntry.solveOccurMultipleFlexions(hDst, oStatsLex)
                oEntry.calcOccurFromFlexions()

            # Fréquences
            echo("   calcul des fréquences et indices de fréquence...")
            for oFlex in self.lFlexions:
                oFlex.calcFreq(self.nTotOccurRecognizedWords)
            for oEntry in self.lEntry:
                oEntry.calcFreq(self.nTotOccurRecognizedWords)

            # Entrées, statistiques
            echo("   statistiques...")
            hDst.write("\n\nNatures grammaticales :\n")
            d = {}
            for oEntry in self.lEntry:
                po = re.sub("(?<=v[0-3])[itnpqrmaezx_]+", "", oEntry.po)
                d[po] = d.get(po, 0) + 1
            for e in sorted(d.items(), key = lambda x: (x[1], x[0]), reverse=True):
                hDst.write(" * {0[1]:<15} : {0[0]}\n".format(e))

            hDst.write("\n\nVentilation des entrées par indice de fréquence :\n")
            d1 = {}
            d2 = {}
            for oEntry in self.lEntry:
                d1[oEntry.fq] = d1.get(oEntry.fq, 0) + 1
                d2[oEntry.fq] = d2.get(oEntry.fq, 0) + oEntry.fFreq
            for k in sorted(d1.keys()):
                hDst.write(" * {} : {} entrées ({:.2f} %)  → {:.9f} %\n".format(k, d1[k], (d1[k]*100)/self.nEntry, d2[k]))

            hDst.write("\n\nRépartition des entrées par sous-dictionnaire :\n")
            d = {}
            for oEntry in self.lEntry:
                d[oEntry.di] = d.get(oEntry.di, 0) + 1
            for sKey, nVal in d.items():
                hDst.write(" * {0:<15} : {1} entrées ({2:.2f} %)\n".format(dSUBDIC[sKey], nVal, (nVal*100)/self.nEntry))

            # Occurrences des lettres
            echo("   occurrences des lettres...")
            d = {}
            for oFlex in self.lFlexions:
                for c in oFlex.sFlexion:
                    d[c] = d.get(c, 0) + oFlex.nOccur
            nTot = 0
................................................................................
            hDst.write("\n\nNombre de formes fléchies : {}\n".format(len(self.lFlexions)))
            hDst.write("\n\nNombre de graphies : {}\n".format(len(self.aFlexions)))

    def calcMetagraphe (self):
        echo(" * Lexique - Metagraphe")
        for oFlex in self.lFlexions:
            oFlex.calcMetagraphe()

    def calcMetaphone2 (self):
        echo(" * Lexique - Metaphone 2")
        for oFlex in self.lFlexions:
            oFlex.calcMetaphone2()

    def createNgrams (self, spDest, n):
        echo(" * Lexique - Ngrams " + str(n))
        if n < 2:
            echo("erreur: n = " + str(n))
            return
        dOccur = {} # ngram:n
        dRefW = {} # ngram:set(idx)
................................................................................
        file_util.copy_file('_templates/ooo/french_flag.png', spExt)
        file_util.copy_file('_templates/ooo/french_flag_16.bmp', spExt+'/ui')
        copyTemplate('_templates/ooo', spExt, 'description.xml', dTplVars)
        copyTemplate('_templates/ooo', spExt, 'dictionaries.xcu', dTplVars)
        #file_util.copy_file('_templates/ooo/dictionaries.xcu.tpl.xml', spExt)
        copyTemplate('_templates/ooo', spExt, 'package-description.txt', dTplVars)
        for dVars in lDictVars:
            dicPath = spBuild + '/' + PREFIX_DICT_PATH + self.sVersion
            file_util.copy_file(dicPath+'/'+dVars['asciiName']+'.dic', spExt+'/dictionaries/'+dVars['asciiName']+'.dic')
            file_util.copy_file(dicPath+'/'+dVars['asciiName']+'.aff', spExt+'/dictionaries/'+dVars['asciiName']+'.aff')
        copyTemplate('orthographe', spExt+'/dictionaries', 'README_dict_fr.txt', dTplVars)
        # thesaurus
        file_util.copy_file('thesaurus/thes_fr.dat', spExt+'/dictionaries')
        file_util.copy_file('thesaurus/thes_fr.idx', spExt+'/dictionaries')
        file_util.copy_file('thesaurus/README_thes_fr.txt', spExt+'/dictionaries')
................................................................................
        file_util.copy_file('césures/README_hyph_fr-2.9.txt', spExt+'/dictionaries')
        # zip
        createZipFiles(spExt, spBuild, sExtensionName + '.oxt')
        # copy to Grammalecte Project
        if spDestGL:
            echo("   extension copiée dans Grammalecte...")
            dir_util.copy_tree(spExt+'/dictionaries', spDestGL)

    def createMozillaExtensions (self, spBuild, dTplVars, lDictVars, spDestGL=""):
        # Mozilla extension 1
        echo(" * Dictionnaire >> extension pour Mozilla")
        dTplVars['version'] = self.sVersion
        sExtensionName = EXT_PREFIX_MOZ + self.sVersion
        spExt = spBuild + '/' + sExtensionName
        dir_util.mkpath(spExt+'/dictionaries')
................................................................................
        createZipFiles(spExt, spBuild, sExtensionName + '.xpi')
        # Grammalecte
        if spDestGL:
            echo(" * Dictionnaire >> copie des dicos dans Grammalecte")
            for dVars in lDictVars:
                file_util.copy_file(spDict+'/'+dVars['asciiName']+'.dic', spDestGL+'/'+dVars['mozAsciiName']+"/"+dVars['mozAsciiName']+'.dic')
                file_util.copy_file(spDict+'/'+dVars['asciiName']+'.aff', spDestGL+'/'+dVars['mozAsciiName']+"/"+dVars['mozAsciiName']+'.aff')

    def createFileIfqForDB (self, spBuild):
        echo(" * Dictionnaire >> indices de fréquence pour la DB...")
        with open(spBuild+'/dictIdxIfq-'+self.sVersion+'.diff.txt', 'w', encoding='utf-8', newline="\n") as hDiff, \
             open(spBuild+'/dictIdxIfq-'+self.sVersion+'.notes.txt', 'w', encoding='utf-8', newline="\n") as hNotes:
            for oEntry in self.lEntry:
                if oEntry.fq != oEntry.oldFq:
                    hDiff.write("{0.iD}\t{0.fq}\n".format(oEntry))
                    hNotes.write("{0.lemma}/{0.flags}\t{0.oldFq} > {0.fq}\n".format(oEntry))

    def createLexiconPackages (self, spBuild, version, oStatsLex, spDestGL=""):
        sLexName = LEX_PREFIX + version
        spLex = spBuild + '/' + sLexName
        dir_util.mkpath(spLex)
        # write Dicollecte lexicon
        self.sortLexiconByFreq()
        self.writeLexicon(spLex + '/' + sLexName + '.txt', version, oStatsLex)
................................................................................
        self.iD = '0'

        # autres
        self.comment = ''
        self.err = ''
        self.nFlexions = 0
        self.lFlexions = []
        self.sStem = ''
        self.nOccur = 0
        self.nAKO = -1   # Average known occurrences
        self.fFreq = 0
        self.oldFq = ''

        sLine = sLine.rstrip(" \n")
        # commentaire
        if '#' in sLine:
            sLine, comment = sLine.split('#', 1)
            self.comment = comment.strip()
        # éléments de la ligne
        elems = sLine.split("\t")
        nElems = len(elems)
        # lemme et drapeaux
        firstElems = elems[0].split('/')
        self.lemma = firstElems[0]
        self.flags = firstElems[1]  if len(firstElems) > 1  else ''
        # morph
        for i in range(1, nElems):
................................................................................
                else:
                    echo('  ## Champ inconnu: {}  dans  {}/{}'.format(fields[0], self.lemma, self.flags))
            else:
                self.err = self.err + elems[i]
        if self.err:
            echo("\n## Erreur dans le dictionnaire : {}".format(self.err))
            echo("   dans : " + self.lemma)

    def __str__ (self):
        return "{0.lemma}/{0.flags} {1}".format(self, self.getMorph(2))

    def check (self):
        sErr = ''
        if self.lemma == '':
            sErr += 'lemme vide'
................................................................................
        if re.search(r"\s$", self.lemma):
            sErr += 'espace en fin de lemme'
        if re.match(r"v[0123]", self.po) and not re.match(r"[eas_][ix_][tx_][nx_][pqreuvx_][mx_][ex_z][ax_z]\b", self.po[2:]):
            sErr += 'verbe inconnu: ' + self.po
        if (re.match(r"S[*.]", self.flags) and re.search("[sxz]$", self.lemma)) or (re.match(r"X[*.]", self.flags) and not re.search("[ul]$", self.lemma)):
            sErr += 'drapeau inutile'
        if self.iz == '' and re.match(r"[SXAI](?!=)", self.flags) and self.po:
            sErr += '[is] vide'
        if re.match(r"pl|sg|inv", self.iz):
            sErr += '[is] incomplet'
        if re.match(r"[FW]", self.flags) and re.search(r"epi|mas|fem|inv|sg|pl", self.iz):
            sErr += '[is] incohérent'
        if re.match(r"[FW]", self.flags) and re.search(r"[^eë]$", self.lemma):
            sErr += "fin de lemme inapproprié"
        if re.match(r".\*", self.flags) and re.match(r"[bcdfgjklmnpqrstvwxz]", self.lemma):
            sErr += 'drapeau pour lemme commençant par une voyelle'
        if re.search(r"pl|sg|inv", self.iz) and re.match(r"[SXAIFW](?!=)", self.flags):
            sErr += '[is] incohérent'
        if re.search(r"nom|adj", self.po) and re.match(r"(?i)[aâàäáeéèêëiîïíìoôöóòuûüúù]", self.lemma) and re.match("[SFWXAI][.]", self.flags) \
           and "pel" not in self.lx:
            sErr += 'le drapeau derait finir avec *'
        if not self.flags and self.iz.endswith(("mas", "fem", "epi")):
            sErr += '[is] incomplet'
        if self.flags.startswith(("a", "b", "c", "d")) and not self.lemma.endswith("er"):
            sErr += "drapeau pour verbe du 1ᵉʳ groupe sur un lemme non conforme"
................................................................................

    def keyTriNat (self):
        return (self.lemma.translate(CHARMAP), self.flags, self.po)

    def keyTriNum (self):
        return (self.lemma, self.flags, self.po)

    def getHunspellLine (self, oDict, nMode, bSimplified=False):
        sLine = self.lemma.replace("’", "'")
        if self.flags:
            sLine += '/'
            sLine += self.flags  if not oDict.bShortenTags or bSimplified  else oDict.dAF[self.flags]
        if bSimplified:
            return sLine.replace("()", "") + "\n"
        if nMode > 0:
            sMorph = self.getMorph(nMode)
................................................................................
                if not sMorph.endswith((" mas", " fem", " epi")):
                    self.lFlexions.append( Flexion(self, sFlex, sMorph, sDic) )
                    self.nFlexions += 1
                else:
                    #echo(sFlex + " " + sMorph + ", ")
                    pass
        # Drapeaux dont le lemme féminin doit être remplacé par le masculin dans la gestion des formes fléchies
        if self.st:
            self.sStem = self.st
        else:
            if self.flags.startswith(("F.", "F*", "W.", "W*")):
                # recherche de la forme masculine
                for t in lTuples:
                    sMorph = self.clean(t[1])


                    if sMorph.endswith(('mas', 'mas sg', 'mas inv')):
                        self.sStem = t[0]
            else:
                self.sStem = self.lemma
        # Tag duplicates
        d = {}
        for oFlex in self.lFlexions:
            d[oFlex.sFlexion] = d.get(oFlex.sFlexion, 0) + 1
        for oFlex in self.lFlexions:
            oFlex.nDup = d[oFlex.sFlexion]

................................................................................
                                        lFlexions.append( (oRule.add+flex[0], flex[1]+ruleMorph) )
                                else:
                                    lFlexions.append(flexion)
                            else:
                                flexion = (self.lemma.replace(oRule.cut, oRule.add, 1), ruleMorph+morph, oRule.di)
                                if oFlag.bMix:
                                    lFlexPrefix.append(flexion)
                                    for flex in lFlexSuffix:
                                        lFlexions.append( (flex[0].replace(oRule.cut, oRule.add, 1), flex[1]+ruleMorph) )
                                else:
                                    lFlexions.append(flexion)
                            if oRule.flags != '' and oRule.flags != '**':
                                lFlexions.extend(Entree(flexion[0]+'/'+oRule.flags)._flechir(dFlags, flexion[1], iPR+1))
                else:
                    # cas des suffixes
................................................................................
    def calcOccurFromFlexions (self):
        self.nOccur = 0
        for o in self.lFlexions:
            self.nOccur += o.nOccur

    def calcAverageKnownOccurrence (self):
        # nous calculons la moyenne des occurrences des formes fléchies
        # qui n’ont pas d’équivalent dans les autres entrées (nMulti = 0)
        nOccur = 0
        nFlex = 0
        for oFlex in self.lFlexions:
            if oFlex.nMulti == 0:
                nOccur += oFlex.nOccur
                nFlex += 1
        # moyenne des formes fléchies sans équivalent ou -1
        self.nAKO = math.ceil(nOccur / nFlex)  if nFlex > 0  else -1

    def solveOccurMultipleFlexions (self, hDst, oStatsLex):
        sBlank = "           "
        if self.nAKO >= 0:
            for oFlex in self.lFlexions:
                if oFlex.nMulti > 0 and not oFlex.bBlocked:
                    # on trie les entrées avec AKO et sans AKO
                    lEntWithAKO = []
                    lEntNoAKO = []
                    for oEntry in oFlex.lMulti:
                        if oEntry.nAKO >= 0:
                            lEntWithAKO.append(oEntry)
                        else:
                            lEntNoAKO.append(oEntry)

                    if lEntNoAKO:
                        # on calcule la différence totale occasionnée par du passage des flexions appartenant à des entrées avec AKO au niveau AKO
                        nDiff = (oFlex.nOccur - self.nAKO) * oFlex.nDup
                        for oEntry in lEntWithAKO:
                            for oFlexM in oEntry.lFlexions:
                                if oFlex.sFlexion == oFlexM.sFlexion:
                                    nDiff += oFlexM.nOccur - oEntry.nAKO
................................................................................
                                        oFlexM.setOccurAndBlock(nNewOccur)
                    else:
                        # Toutes les entrées sont avec AKO : on pondère
                        nFlexOccur = oStatsLex.getFlexionOccur(oFlex.sFlexion)
                        nTotAKO = self.nAKO
                        for oEnt in oFlex.lMulti:
                            nTotAKO += oEnt.nAKO

                        hDst.write(" = {0.sFlexion}\n".format(oFlex))
                        hDst.write("       moyennes connues\n")
                        for oFlexD in self.lFlexions:
                            if oFlex.sFlexion == oFlexD.sFlexion:
                                nNewOccur = math.ceil((nFlexOccur * (self.nAKO / nTotAKO)) / oFlexD.nDup)  if nTotAKO  else 0
                                hDst.write(sBlank + "{2:<30} {0.sMorph:<30}  {0.nOccur:>10}  %> {1:>10}\n".format(oFlexD, nNewOccur, self.getShortDescr()))
                                oFlexD.setOccurAndBlock(nNewOccur)
                        for oEntry in oFlex.lMulti:
                            for oFlexM in oEntry.lFlexions:
                                if oFlex.sFlexion == oFlexM.sFlexion:
                                    nNewOccur = math.ceil((nFlexOccur * (oEntry.nAKO / nTotAKO)) / oFlexM.nDup)  if nTotAKO  else 0
                                    hDst.write(sBlank + "{2:<30} {0.sMorph:<30}  {0.nOccur:>10}  %> {1:>10}\n".format(oFlexM, nNewOccur, oEntry.getShortDescr()))
                                    oFlexM.setOccurAndBlock(nNewOccur)

    def calcFreq (self, nTot):
        self.fFreq = (self.nOccur * 100) / nTot
        self.oldFq = self.fq
        self.fq = getIfq(self.fFreq)



................................................................................
        self.nDup    = 0    # duplicates in the same entry
        self.nMulti  = 0    # duplicates with other entries
        self.lMulti  = []   # list of similar flexions
        self.fFreq   = 0
        self.cFq     = ''
        self.metagfx = ''   # métagraphe
        self.metaph2 = ''   # métaphone 2

    def setOccur (self, n):
        self.nOccur = n

    def setOccurAndBlock (self, n):
        self.nOccur = n
        self.bBlocked = True

    def calcOccur (self):
        self.nOccur = math.ceil((self.nOccur / (self.nMulti+1)) / self.nDup)

    def calcFreq (self, nTot):
        self.fFreq = (self.nOccur * 100) / nTot
        self.cFq = getIfq(self.fFreq)

    def calcMetagraphe (self):
        t = metagraphe.getMetagraphe(self.sFlexion, self.sMorph)
        self.metagfx = t[0]  if not t[1]  else t[0]+"/"+t[1]

    def calcMetaphone2 (self):
        t = metaphone2.dm(self.sFlexion)
        self.metaph2 = t[0]  if not t[1]  else t[0]+"/"+t[1]
................................................................................
            sOccurs += t[1] + "\t"
        return "id\tFlexion\tLemme\tÉtiquettes\tMétagraphe (β)\tMetaphone2\tNotes\tSémantique\tÉtymologie\tSous-dictionnaire\t" + sOccurs + "Total occurrences\tDoublons\tMultiples\tFréquence\tIndice de fréquence\n"

    def __str__ (self, oStatsLex):
        sOccurs = ''
        for v in oStatsLex.dFlexions[self.sFlexion]:
            sOccurs += str(v) + "\t"
        return "{0.oEntry.iD}\t{0.sFlexion}\t{0.oEntry.sStem}\t{0.sMorph}\t{0.metagfx}\t{0.metaph2}\t{0.oEntry.lx}\t{0.oEntry.se}\t{0.oEntry.et}\t{0.oEntry.di}{2}\t{1}{0.nOccur}\t{0.nDup}\t{0.nMulti}\t{0.fFreq:.15f}\t{0.cFq}\n".format(self, sOccurs, "/"+self.cDic if self.cDic != "*" else "")

    @classmethod
    def simpleHeader (cls):
        return "# :POS ;LEX ~SEM =FQ /DIC\n"

    def getGrammarCheckerRepr (self):
        return "{0.sFlexion}\t{0.oEntry.lemma}\t{1}\n".format(self, self._getSimpleTags())
................................................................................
        "ipre": ":Ip", "iimp": ":Iq", "ipsi": ":Is", "ifut": ":If",
        "spre": ":Sp", "simp": ":Sq", "cond": ":K", "impe": ":E",
        "1sg": ":1s", "1isg": ":1ś", "1jsg": ":1ŝ", "2sg": ":2s", "3sg": ":3s", "1pl": ":1p", "2pl": ":2p", "3pl": ":3p", "3pl!": ":3p!",
        "prepv": ":Rv", "prep": ":R", "loc.prep": ":Ŕ",
        "detpos": ":Dp", "detdem": ":Dd", "detind": ":Di", "detneg": ":Dn", "detex": ":De", "det": ":D",
        "advint": ":U",
        "prodem": ":Od", "proind": ":Oi", "proint": ":Ot", "proneg": ":On", "prorel": ":Or", "proadv": ":Ow",
        "properobj": ":Oo", "propersuj": ":Os", "1pe": ":O1", "2pe": ":O2", "3pe": ":O3", "preverb": ":Ov",
        "cjco": ":Cc", "cjsub": ":Cs", "cj": ":C", "loc.cj": ":Ĉ", "loc.cjsub": ":Ĉs",
        "prn": ":M1", "patr": ":M2", "loc.patr": ":Ḿ2", "npr": ":MP", "nompr": ":NM",
        "pfx": ":Zp", "sfx": ":Zs",
        "div": ":H",
        "err": ":#",
        # LEX
        "symb": ";S"
................................................................................
            s += "/" + self.oEntry.di
        return s

    def keyTriNat (self):
        return (self.sFlexion.translate(CHARMAP), self.sMorph)

    def keyFreq (self):
        return (100-self.fFreq, self.oEntry.sStem, self.sFlexion)

    def keyOcc (self):
        return (self.nOccur, self.oEntry.sStem, self.sFlexion)

    def keyIdx (self):
        return self.oEntry.iD

    def keyFlexion (self):
        return self.sFlexion


................................................................................
    def __init__ (self, sFlagType, sFlagName, sMix):
        self.sFlagName = sFlagName
        self.bSfx = True  if sFlagType == 'SFX'  else False
        self.bMix = True  if sMix == 'Y'  else False
        self.lRules = []
        self.nRules = 0
        self.nOccur = 0

    def addAffixRule (self, line):
        "ajoute une règle au drapeau"
        oRule = AffixRule(line)
        self.lRules.append(oRule)
        self.nRules += 1

    def getFlag (self, subDicts, oDict, nMode, bSimplified):
................................................................................
        # champs de Dicollecte
        self.lx = ''
        self.di = '*'
        # erreurs
        self.err = ''
        # autres champs
        self.nOccur = 0

        sLine = sLine.rstrip(" \n")
        # commentaire
        if '#' in sLine:
            sLine, comment = sLine.split('#', 1)
            self.comment = comment.strip()
        # éléments de la ligne
        elems = sLine.split()
................................................................................
                    self.lx = fields[1]  if self.lx == ''  else self.lx + ' ' + fields[1]
                elif fields[0] == 'di':
                    self.di = fields[1]
                else:
                    echo('Champ inconnu: {}  dans  {}'.format(fields[0], self.sFlagName))
            else:
                echo("  # Erreur affixe : {}".format(line))

    def isReplicationRule (self):
        "is this rule used for replication of a virtual lemma"
        return self.flags == "" and ((self.cut == "0" and self.add == "") or self.cut == self.add)

    def getRuleLine (self, oDict, nMode, bSimplified=False):
        sLine = 'SFX'  if self.bSfx  else 'PFX'
        sLine += ' ' + self.sFlagName + ' ' + self.cut + ' '
................................................................................
                sLine = sLine.replace("()", "")
        sLine += ' ' + self.cond
        if not bSimplified and nMode > 0:
            sMorph = self.getMorph(nMode)
            if sMorph:
                sLine += sMorph  if not oDict.bShortenTags or bSimplified  else ' ' + oDict.dAM[sMorph.strip()]
        return sLine + "\n"

    def getMorph (self, nMode):
        # morphology for Hunspell
        txt = ''
        if self.po: txt += fieldToHunspell('po', self.po)
        if self.iz: txt += fieldToHunspell('is', self.iz)
        if self.ds: txt += fieldToHunspell('ds', self.ds)
        if self.ts: txt += fieldToHunspell('ts', self.ts)
................................................................................


class StatsLex:
    def __init__ (self, oDict):
        echo("Lexique statistique")
        self.dFlexions = { oFlex.sFlexion: []  for oFlex in oDict.lFlexions }
        self.lLex = []

    def addLexFromFile (self, sPathFile, cLexID, sLexName):
        if not os.path.isfile(sPathFile):
            echo(' * Lexique statistique - fichier {} introuvable'.format(sPathFile))
            return None
        if len(cLexID) != 1:
            echo(' * Lexique statistique - fichier {} - identifiant incorrect, 1 caractère requis'.format(sPathFile))
            return None
................................................................................
                hDst.write(str(t)+"\n")
            for e in self.dFlexions.items():
                hDst.write("{} - {}\n".format(e[0], e[1]))



def main ():

    xParser = argparse.ArgumentParser()
    xParser.add_argument("-v", "--verdic", help="set dictionary version, i.e. 5.4", type=str, default="X.Y.z")
    xParser.add_argument("-m", "--mode", help="0: no tags,  1: Hunspell tags (default),  2: All tags", type=int, choices=[0, 1, 2], default=1)
    xParser.add_argument("-u", "--uncompress", help="do not use Hunspell compression", action="store_true")
    xParser.add_argument("-s", "--simplify", help="no virtual lemmas", action="store_true")
    xParser.add_argument("-sv", "--spellvariants", help="generate spell variants", action="store_true")
    xParser.add_argument("-gl", "--grammalecte", help="copy generated files to Grammalecte folders", action="store_true")
................................................................................
        xArgs.uncompress = True

    echo("Python: " + sys.version)
    echo("Version: " + xArgs.verdic)
    echo("Simplify: " + str(xArgs.simplify))
    echo("Mode: " + str(xArgs.mode))
    echo("Compression: " + str(not(xArgs.uncompress)))

    ### création du répertoire
    spBuild = BUILD_PATH + '/' + xArgs.verdic
    dir_util.mkpath(spBuild)

    ### Lecture des fichiers et création du dictionnaire
    oFrenchDict = Dictionnaire(xArgs.verdic, "French dictionary")
    for sFile in ['orthographe/FRANCAIS.dic']:
        oFrenchDict.readDictionary(sFile)
    oFrenchDict.readAffixes('orthographe/FRANCAIS_5.aff')

    ### Contrôle
    oFrenchDict.sortEntriesNatural()
    oFrenchDict.checkEntries()

    ### Lexique
    oFrenchDict.generateFlexions()
    oFrenchDict.calcMetagraphe()
    oFrenchDict.calcMetaphone2()

    #oFrenchDict.createNgrams(spBuild, 3)
    if xArgs.spellvariants:
................................................................................
    oStatsLex = StatsLex(oFrenchDict)
    oStatsLex.addLexFromFile('lexique/corpus_data/stats_google_ngram_1.txt', 'G', 'Google 1-grams')
    oStatsLex.addLexFromFile('lexique/corpus_data/stats_frwiki.txt', 'W', 'Wikipédia')
    oStatsLex.addLexFromFile('lexique/corpus_data/stats_frwikisource.txt', 'S', 'Wikisource')
    oStatsLex.addLexFromFile('lexique/corpus_data/stats_litterature.txt', 'L', 'Littérature')
    oStatsLex.write(spBuild+'/test_lex.txt')
    oFrenchDict.calculateStats(oStatsLex, spfStats)

    ### écriture des paquets
    echo("Création des paquets...")

    spLexiconDestGL = "../../../lexicons"  if xArgs.grammalecte  else ""
    spLibreOfficeExtDestGL = "../oxt/Dictionnaires/dictionaries"  if xArgs.grammalecte  else ""
    spMozillaExtDestGL = ""  if xArgs.grammalecte  else "" # no more Hunspell dictionaries in Mozilla extensions for now
    spDataDestGL = "../data"  if xArgs.grammalecte  else ""

    if not xArgs.uncompress:
        oFrenchDict.defineAbreviatedTags(xArgs.mode, spfStats)
    oFrenchDict.createFiles(spBuild, [dMODERNE, dTOUTESVAR, dCLASSIQUE, dREFORME1990], xArgs.mode, xArgs.simplify)
    oFrenchDict.createLexiconPackages(spBuild, xArgs.verdic, oStatsLex, spLexiconDestGL)
    oFrenchDict.createFileIfqForDB(spBuild)

Modified gc_lang/fr/dictionnaire/lexique/french.tagset.txt from [b4e8126915] to [4a587bac86].

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
..
90
91
92
93
94
95
96

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
        avec verbe auxilaire être ?         _________________________/  |
        avec verbe auxilaire avoir ?        ____________________________/

    Infinitif                   :Y
    Participe présent           :P
    Participe passé             :Q

    Indicatif présent           :Ip         1re personne du singulier   :1s  (forme interrogative: 1ś ou 1ŝ)
    Indicatif imparfait         :Iq         2e personne du singulier    :2s
    Indicatif passé simple      :Is         3e personne du singulier    :3s
    Indicatif futur             :If         1re personne du pluriel     :1p
                                            2e personne du pluriel      :2p
    Subjonctif présent          :Sp         3e personne du pluriel      :3p
    Subjonctif imparfait        :Sq
    
    Conditionnel                :K
    Impératif                   :E


//  MOTS GRAMMATICAUX

    Mot grammatical                     :G
................................................................................
    pronom indéterminé                  :Oi
    pronom interrogatif                 :Oj
    pronom relatif                      :Or
    pronom de négation                  :On
    pronom adverbial                    :Ow
    pronom personnel sujet              :Os
    pronom personnel objet              :Oo



========== MÉMO ==========

:A  Adjectif
:B  Nombre cardinal
:C  Conjonction
:D  Déterminant
:E  Impératif (verbe)
:F  
:G  Mot grammatical
:H  <Hors-norme>
:I  Indicatif (verbe)
:J  Interjection
:K  Conditionnel (verbe)
:L  Locution
:M  Nom propre (sans article)
................................................................................
:U  Adverbe interrogatif
:V  Verbe (quelle que soit la forme)
:W  Adverbe
:X  Adverbe de négation
:Y  Infinitif (verbe)
:Z  Préfixe ou suffixe

:1  1re personne (verbe)
:2  2e personne (verbe)
:3  3e personne (verbe)

:e  épicène
:f  féminin
:i  invariable
:m  masculin
:p  pluriel
:s  singulier







|
|
|
|
|
|

|







 







>









|







 







|
|
|







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
..
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
        avec verbe auxilaire être ?         _________________________/  |
        avec verbe auxilaire avoir ?        ____________________________/

    Infinitif                   :Y
    Participe présent           :P
    Participe passé             :Q

    Indicatif présent           :Ip         1ʳᵉ personne du singulier   :1s  (forme interrogative: 1ś ou 1ŝ)
    Indicatif imparfait         :Iq         2 personne du singulier    :2s
    Indicatif passé simple      :Is         3 personne du singulier    :3s
    Indicatif futur             :If         1ʳᵉ personne du pluriel     :1p
                                            2 personne du pluriel      :2p
    Subjonctif présent          :Sp         3 personne du pluriel      :3p
    Subjonctif imparfait        :Sq

    Conditionnel                :K
    Impératif                   :E


//  MOTS GRAMMATICAUX

    Mot grammatical                     :G
................................................................................
    pronom indéterminé                  :Oi
    pronom interrogatif                 :Oj
    pronom relatif                      :Or
    pronom de négation                  :On
    pronom adverbial                    :Ow
    pronom personnel sujet              :Os
    pronom personnel objet              :Oo
    préverbe (pron. p. obj. + ne)       :Ov  (l’étiquette pour “ne” est une inexactitude commode)


========== MÉMO ==========

:A  Adjectif
:B  Nombre cardinal
:C  Conjonction
:D  Déterminant
:E  Impératif (verbe)
:F
:G  Mot grammatical
:H  <Hors-norme>
:I  Indicatif (verbe)
:J  Interjection
:K  Conditionnel (verbe)
:L  Locution
:M  Nom propre (sans article)
................................................................................
:U  Adverbe interrogatif
:V  Verbe (quelle que soit la forme)
:W  Adverbe
:X  Adverbe de négation
:Y  Infinitif (verbe)
:Z  Préfixe ou suffixe

:1  1ʳᵉ personne (verbe)
:2  2 personne (verbe)
:3  3 personne (verbe)

:e  épicène
:f  féminin
:i  invariable
:m  masculin
:p  pluriel
:s  singulier

Modified gc_lang/fr/dictionnaire/orthographe/FRANCAIS.dic from [adff056839] to [17edf44273].

more than 10,000 changes

Modified gc_lang/fr/modules-js/conj.js from [f544af05b0] to [8124143953].

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
        return this._lVtyp[this._dVerb[sVerb][0]];
    },

    getSimil: function (sWord, sMorph, bSubst=false) {
        if (!sMorph.includes(":V")) {
            return new Set();
        }
        let sInfi = sMorph.slice(1, sMorph.indexOf(" "));
        let aSugg = new Set();
        let tTags = this._getTags(sInfi);
        if (tTags) {
            if (!bSubst) {
                // we suggest conjugated forms
                if (sMorph.includes(":V1")) {
                    aSugg.add(sInfi);







|







83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
        return this._lVtyp[this._dVerb[sVerb][0]];
    },

    getSimil: function (sWord, sMorph, bSubst=false) {
        if (!sMorph.includes(":V")) {
            return new Set();
        }
        let sInfi = sMorph.slice(1, sMorph.indexOf("/"));
        let aSugg = new Set();
        let tTags = this._getTags(sInfi);
        if (tTags) {
            if (!bSubst) {
                // we suggest conjugated forms
                if (sMorph.includes(":V1")) {
                    aSugg.add(sInfi);

Modified gc_lang/fr/modules-js/gce_analyseur.js from [e2613ddcd2] to [427ee71140].

1
2








3
4
5
6
7
8
9
..
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

44
45
46

47
48
49

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
..
99
100
101
102
103
104
105
106
107
108
109
110
111

112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
//// GRAMMAR CHECKING ENGINE PLUGIN: Parsing functions for French language
/*jslint esversion: 6*/









function rewriteSubject (s1, s2) {
    // s1 is supposed to be prn/patr/npr (M[12P])
    if (s2 == "lui") {
        return "ils";
    }
    if (s2 == "moi") {
................................................................................
    if (s2 == "vous") {
        return "vous";
    }
    if (s2 == "eux") {
        return "ils";
    }
    if (s2 == "elle" || s2 == "elles") {
        // We don’t check if word exists in _dAnalyses, for it is assumed it has been done before
        if (cregex.mbNprMasNotFem(_dAnalyses.gl_get(s1, ""))) {
            return "ils";
        }
        // si épicène, indéterminable, mais OSEF, le féminin l’emporte
        return "elles";
    }
    return s1 + " et " + s2;
}

function apposition (sWord1, sWord2) {
    // returns true if nom + nom (no agreement required)
    // We don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    return cregex.mbNomNotAdj(_dAnalyses.gl_get(sWord2, "")) && cregex.mbPpasNomNotAdj(_dAnalyses.gl_get(sWord1, ""));
}

function isAmbiguousNAV (sWord) {
    // words which are nom|adj and verb are ambiguous (except être and avoir)
    if (!_dAnalyses.has(sWord) && !_storeMorphFromFSA(sWord)) {

        return false;
    }
    if (!cregex.mbNomAdj(_dAnalyses.gl_get(sWord, "")) || sWord == "est") {

        return false;
    }
    if (cregex.mbVconj(_dAnalyses.gl_get(sWord, "")) && !cregex.mbMG(_dAnalyses.gl_get(sWord, ""))) {

        return true;
    }
    return false;
}

function isAmbiguousAndWrong (sWord1, sWord2, sReqMorphNA, sReqMorphConj) {
    //// use it if sWord1 won’t be a verb; word2 is assumed to be true via isAmbiguousNAV
    // We don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    let a2 = _dAnalyses.gl_get(sWord2, null);
    if (!a2 || a2.length === 0) {
        return false;
    }
    if (cregex.checkConjVerb(a2, sReqMorphConj)) {
        // verb word2 is ok
        return false;
    }
    let a1 = _dAnalyses.gl_get(sWord1, null);
    if (!a1 || a1.length === 0) {
        return false;
    }
    if (cregex.checkAgreement(a1, a2) && (cregex.mbAdj(a2) || cregex.mbAdj(a1))) {
        return false;
    }
    return true;
}

function isVeryAmbiguousAndWrong (sWord1, sWord2, sReqMorphNA, sReqMorphConj, bLastHopeCond) {
    //// use it if sWord1 can be also a verb; word2 is assumed to be true via isAmbiguousNAV
    // We don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    let a2 = _dAnalyses.gl_get(sWord2, null);
    if (!a2 || a2.length === 0) {
        return false;
    }
    if (cregex.checkConjVerb(a2, sReqMorphConj)) {
        // verb word2 is ok
        return false;
    }
    let a1 = _dAnalyses.gl_get(sWord1, null);
    if (!a1 || a1.length === 0) {
        return false;
    }
    if (cregex.checkAgreement(a1, a2) && (cregex.mbAdj(a2) || cregex.mbAdjNb(a1))) {
        return false;
    }
    // now, we know there no agreement, and conjugation is also wrong
    if (cregex.isNomAdj(a1)) {
................................................................................
    if (bLastHopeCond) {
        return true;
    }
    return false;
}

function checkAgreement (sWord1, sWord2) {
    // We don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    let a2 = _dAnalyses.gl_get(sWord2, null);
    if (!a2 || a2.length === 0) {
        return true;
    }
    let a1 = _dAnalyses.gl_get(sWord1, null);

    if (!a1 || a1.length === 0) {
        return true;
    }
    return cregex.checkAgreement(a1, a2);
}

function mbUnit (s) {
    if (/[µ\/⁰¹²³⁴⁵⁶⁷⁸⁹Ωℓ·]/.test(s)) {
        return true;
    }
    if (s.length > 1 && s.length < 16 && s.slice(0, 1).gl_isLowerCase() && (!s.slice(1).gl_isLowerCase() || /[0-9]/.test(s))) {
        return true;
    }
    return false;
}


//// Syntagmes

const _zEndOfNG1 = new RegExp ("^ *$|^ +(?:, +|)(?:n(?:’|e |o(?:u?s|tre) )|l(?:’|e(?:urs?|s|) |a )|j(?:’|e )|m(?:’|es? |a |on )|t(?:’|es? |a |u )|s(?:’|es? |a )|c(?:’|e(?:t|tte|s|) )|ç(?:a |’)|ils? |vo(?:u?s|tre) )");
const _zEndOfNG2 = new RegExp ("^ +([a-zà-öA-Zø-ÿÀ-Ö0-9_Ø-ßĀ-ʯ][a-zà-öA-Zø-ÿÀ-Ö0-9_Ø-ßĀ-ʯ-]+)");
const _zEndOfNG3 = new RegExp ("^ *, +([a-zà-öA-Zø-ÿÀ-Ö0-9_Ø-ßĀ-ʯ][a-zà-öA-Zø-ÿÀ-Ö0-9_Ø-ßĀ-ʯ-]+)");

function isEndOfNG (dDA, s, iOffset) {
    if (_zEndOfNG1.test(s)) {
        return true;
    }
    let m = _zEndOfNG2.gl_exec2(s, ["$"]);
    if (m && morphex(dDA, [iOffset+m.start[1], m[1]], ":[VR]", ":[NAQP]")) {
        return true;
    }
    m = _zEndOfNG3.gl_exec2(s, ["$"]);
    if (m && !morph(dDA, [iOffset+m.start[1], m[1]], ":[NA]", false)) {
        return true;
    }
    return false;
}


const _zNextIsNotCOD1 = new RegExp ("^ *,");
const _zNextIsNotCOD2 = new RegExp ("^ +(?:[mtsnj](e +|’)|[nv]ous |tu |ils? |elles? )");
const _zNextIsNotCOD3 = new RegExp ("^ +([a-zéèî][a-zà-öA-Zø-ÿÀ-ÖØ-ßĀ-ʯ-]+)");

function isNextNotCOD (dDA, s, iOffset) {
    if (_zNextIsNotCOD1.test(s) || _zNextIsNotCOD2.test(s)) {
        return true;
    }
    let m = _zNextIsNotCOD3.gl_exec2(s, ["$"]);
    if (m && morphex(dDA, [iOffset+m.start[1], m[1]], ":[123][sp]", ":[DM]")) {
        return true;
    }
    return false;
}


const _zNextIsVerb1 = new RegExp ("^ +[nmts](?:e |’)");
const _zNextIsVerb2 = new RegExp ("^ +([a-zà-öA-Zø-ÿÀ-Ö0-9_Ø-ßĀ-ʯ][a-zà-öA-Zø-ÿÀ-Ö0-9_Ø-ßĀ-ʯ-]+)");

function isNextVerb (dDA, s, iOffset) {
    if (_zNextIsVerb1.test(s)) {
        return true;
    }
    let m = _zNextIsVerb2.gl_exec2(s, ["$"]);
    if (m && morph(dDA, [iOffset+m.start[1], m[1]], ":[123][sp]", false)) {
        return true;
    }
    return false;
}


//// Exceptions

const aREGULARPLURAL = new Set(["abricot", "amarante", "aubergine", "acajou", "anthracite", "brique", "caca", "café",
                                "carotte", "cerise", "chataigne", "corail", "citron", "crème", "grave", "groseille",
                                "jonquille", "marron", "olive", "pervenche", "prune", "sable"]);
const aSHOULDBEVERB = new Set(["aller", "manger"]);


>
>
>
>
>
>
>
>







 







<
|










|
<




|
>


<
>


<
>







|
<
|






|
|










|
<
|






|
|







 







|
<
|


<
>
|












<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
..
26
27
28
29
30
31
32

33
34
35
36
37
38
39
40
41
42
43
44

45
46
47
48
49
50
51
52

53
54
55

56
57
58
59
60
61
62
63
64

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
...
104
105
106
107
108
109
110
111

112
113
114

115
116
117
118
119
120
121
122
123
124
125
126
127
128





















































129
130
131
132
133
134
135
136
137
138
//// GRAMMAR CHECKING ENGINE PLUGIN: Parsing functions for French language
/*jslint esversion: 6*/

function g_morphVC (dToken, sPattern, sNegPattern="") {
    let nEnd = dToken["sValue"].lastIndexOf("-");
    if (dToken["sValue"].includes("-t-")) {
        nEnd = nEnd - 2;
    }
    return g_morph(dToken, sPattern, sNegPattern, 0, nEnd, false);
}

function rewriteSubject (s1, s2) {
    // s1 is supposed to be prn/patr/npr (M[12P])
    if (s2 == "lui") {
        return "ils";
    }
    if (s2 == "moi") {
................................................................................
    if (s2 == "vous") {
        return "vous";
    }
    if (s2 == "eux") {
        return "ils";
    }
    if (s2 == "elle" || s2 == "elles") {

        if (cregex.mbNprMasNotFem(_oSpellChecker.getMorph(s1))) {
            return "ils";
        }
        // si épicène, indéterminable, mais OSEF, le féminin l’emporte
        return "elles";
    }
    return s1 + " et " + s2;
}

function apposition (sWord1, sWord2) {
    // returns true if nom + nom (no agreement required)
    return sWord2.length < 2 || (cregex.mbNomNotAdj(_oSpellChecker.getMorph(sWord2)) && cregex.mbPpasNomNotAdj(_oSpellChecker.getMorph(sWord1)));

}

function isAmbiguousNAV (sWord) {
    // words which are nom|adj and verb are ambiguous (except être and avoir)
    let lMorph = _oSpellChecker.getMorph(sWord);
    if (lMorph.length === 0) {
        return false;
    }

    if (!cregex.mbNomAdj(lMorph) || sWord == "est") {
        return false;
    }

    if (cregex.mbVconj(lMorph) && !cregex.mbMG(lMorph)) {
        return true;
    }
    return false;
}

function isAmbiguousAndWrong (sWord1, sWord2, sReqMorphNA, sReqMorphConj) {
    //// use it if sWord1 won’t be a verb; word2 is assumed to be true via isAmbiguousNAV
    let a2 = _oSpellChecker.getMorph(sWord2);

    if (a2.length === 0) {
        return false;
    }
    if (cregex.checkConjVerb(a2, sReqMorphConj)) {
        // verb word2 is ok
        return false;
    }
    let a1 = _oSpellChecker.getMorph(sWord1);
    if (a1.length === 0) {
        return false;
    }
    if (cregex.checkAgreement(a1, a2) && (cregex.mbAdj(a2) || cregex.mbAdj(a1))) {
        return false;
    }
    return true;
}

function isVeryAmbiguousAndWrong (sWord1, sWord2, sReqMorphNA, sReqMorphConj, bLastHopeCond) {
    //// use it if sWord1 can be also a verb; word2 is assumed to be true via isAmbiguousNAV
    let a2 = _oSpellChecker.getMorph(sWord2);

    if (a2.length === 0) {
        return false;
    }
    if (cregex.checkConjVerb(a2, sReqMorphConj)) {
        // verb word2 is ok
        return false;
    }
    let a1 = _oSpellChecker.getMorph(sWord1);
    if (a1.length === 0) {
        return false;
    }
    if (cregex.checkAgreement(a1, a2) && (cregex.mbAdj(a2) || cregex.mbAdjNb(a1))) {
        return false;
    }
    // now, we know there no agreement, and conjugation is also wrong
    if (cregex.isNomAdj(a1)) {
................................................................................
    if (bLastHopeCond) {
        return true;
    }
    return false;
}

function checkAgreement (sWord1, sWord2) {
    let a2 = _oSpellChecker.getMorph(sWord2);

    if (a2.length === 0) {
        return true;
    }

    let a1 = _oSpellChecker.getMorph(sWord1);
    if (a1.length === 0) {
        return true;
    }
    return cregex.checkAgreement(a1, a2);
}

function mbUnit (s) {
    if (/[µ\/⁰¹²³⁴⁵⁶⁷⁸⁹Ωℓ·]/.test(s)) {
        return true;
    }
    if (s.length > 1 && s.length < 16 && s.slice(0, 1).gl_isLowerCase() && (!s.slice(1).gl_isLowerCase() || /[0-9]/.test(s))) {
        return true;
    }





















































    return false;
}


//// Exceptions

const aREGULARPLURAL = new Set(["abricot", "amarante", "aubergine", "acajou", "anthracite", "brique", "caca", "café",
                                "carotte", "cerise", "chataigne", "corail", "citron", "crème", "grave", "groseille",
                                "jonquille", "marron", "olive", "pervenche", "prune", "sable"]);
const aSHOULDBEVERB = new Set(["aller", "manger"]);

Modified gc_lang/fr/modules-js/gce_suggestions.js from [0c31bc1a27] to [dfa4abac25].

7
8
9
10
11
12
13













14
15




16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
..
50
51
52
53
54
55
56



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
...
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125




126
127
128
129
130
131
132
133
134
...
135
136
137
138
139
140
141



142
143
144
145
146
147
148
149
150
151
152
153
154
155
...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
...
193
194
195
196
197
198
199
200

201
202
203
204
205
206
207
208
209
210
...
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
...
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
...
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
...
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
...
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
...
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
...
486
487
488
489
490
491
492
493
494




495
496
497
498
499
500
501



502
503
504
505
506
507
508
...
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
    var mfsp = require("resource://grammalecte/fr/mfsp.js");
    var phonet = require("resource://grammalecte/fr/phonet.js");
}


//// verbs














function suggVerb (sFlex, sWho, funcSugg2=null) {
    // we don’t check if word exists in _dAnalyses, for it is assumed it has been done before




    let aSugg = new Set();
    for (let sStem of stem(sFlex)) {
        let tTags = conj._getTags(sStem);
        if (tTags) {
            // we get the tense
            let aTense = new Set();
            for (let sMorph of _dAnalyses.gl_get(sFlex, [])) {
                let m;
                let zVerb = new RegExp (">"+sStem+" .*?(:(?:Y|I[pqsf]|S[pq]|K))", "g");
                while ((m = zVerb.exec(sMorph)) !== null) {
                    // stem must be used in regex to prevent confusion between different verbs (e.g. sauras has 2 stems: savoir and saurer)
                    if (m) {
                        if (m[1] === ":Y") {
                            aTense.add(":Ip");
                            aTense.add(":Iq");
                            aTense.add(":Is");
................................................................................
    if (funcSugg2) {
        let aSugg2 = funcSugg2(sFlex);
        if (aSugg2.size > 0) {
            aSugg.add(aSugg2);
        }
    }
    if (aSugg.size > 0) {



        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggVerbPpas (sFlex, sWhat=null) {
    let aSugg = new Set();
    for (let sStem of stem(sFlex)) {
        let tTags = conj._getTags(sStem);
        if (tTags) {
            if (!sWhat) {
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"));
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q2"));
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q3"));
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q4"));
................................................................................
        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggVerbTense (sFlex, sTense, sWho) {
    let aSugg = new Set();
    for (let sStem of stem(sFlex)) {
        if (conj.hasConj(sStem, sTense, sWho)) {
            aSugg.add(conj.getConj(sStem, sTense, sWho));
        }
    }
    if (aSugg.size > 0) {
        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggVerbImpe (sFlex) {




    let aSugg = new Set();
    for (let sStem of stem(sFlex)) {
        let tTags = conj._getTags(sStem);
        if (tTags) {
            if (conj._hasConjWithTags(tTags, ":E", ":2s")) {
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":E", ":2s"));
            }
            if (conj._hasConjWithTags(tTags, ":E", ":1p")) {
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":E", ":1p"));
................................................................................
            }
            if (conj._hasConjWithTags(tTags, ":E", ":2p")) {
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":E", ":2p"));
            }
        }
    }
    if (aSugg.size > 0) {



        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggVerbInfi (sFlex) {
    return stem(sFlex).filter(sStem => conj.isVerb(sStem)).join("|");
}


const _dQuiEst = new Map ([
    ["je", ":1s"], ["j’", ":1s"], ["j’en", ":1s"], ["j’y", ":1s"],
    ["tu", ":2s"], ["il", ":3s"], ["on", ":3s"], ["elle", ":3s"],
    ["nous", ":1p"], ["vous", ":2p"], ["ils", ":3p"], ["elles", ":3p"]
................................................................................
    if (!sWho) {
        if (sSuj[0].gl_isLowerCase()) { // pas un pronom, ni un nom propre
            return "";
        }
        sWho = ":3s";
    }
    let aSugg = new Set();
    for (let sStem of stem(sFlex)) {
        let tTags = conj._getTags(sStem);
        if (tTags) {
            for (let sTense of lMode) {
                if (conj._hasConjWithTags(tTags, sTense, sWho)) {
                    aSugg.add(conj._getConjWithTags(sStem, tTags, sTense, sWho));
                }
            }
................................................................................
}

//// Nouns and adjectives

function suggPlur (sFlex, sWordToAgree=null) {
    // returns plural forms assuming sFlex is singular
    if (sWordToAgree) {
        if (!_dAnalyses.has(sWordToAgree) && !_storeMorphFromFSA(sWordToAgree)) {

            return "";
        }
        let sGender = cregex.getGender(_dAnalyses.gl_get(sWordToAgree, []));
        if (sGender == ":m") {
            return suggMasPlur(sFlex);
        } else if (sGender == ":f") {
            return suggFemPlur(sFlex);
        }
    }
    let aSugg = new Set();
................................................................................
        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggMasSing (sFlex, bSuggSimil=false) {
    // returns masculine singular forms
    // we don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    let aSugg = new Set();
    for (let sMorph of _dAnalyses.gl_get(sFlex, [])) {
        if (!sMorph.includes(":V")) {
            // not a verb
            if (sMorph.includes(":m") || sMorph.includes(":e")) {
                aSugg.add(suggSing(sFlex));
            } else {
                let sStem = cregex.getLemmaOfMorph(sMorph);
                if (mfsp.isFemForm(sStem)) {
................................................................................
        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggMasPlur (sFlex, bSuggSimil=false) {
    // returns masculine plural forms
    // we don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    let aSugg = new Set();
    for (let sMorph of _dAnalyses.gl_get(sFlex, [])) {
        if (!sMorph.includes(":V")) {
            // not a verb
            if (sMorph.includes(":m") || sMorph.includes(":e")) {
                aSugg.add(suggPlur(sFlex));
            } else {
                let sStem = cregex.getLemmaOfMorph(sMorph);
                if (mfsp.isFemForm(sStem)) {
................................................................................
    }
    return "";
}


function suggFemSing (sFlex, bSuggSimil=false) {
    // returns feminine singular forms
    // we don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    let aSugg = new Set();
    for (let sMorph of _dAnalyses.gl_get(sFlex, [])) {
        if (!sMorph.includes(":V")) {
            // not a verb
            if (sMorph.includes(":f") || sMorph.includes(":e")) {
                aSugg.add(suggSing(sFlex));
            } else {
                let sStem = cregex.getLemmaOfMorph(sMorph);
                if (mfsp.isFemForm(sStem)) {
................................................................................
        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggFemPlur (sFlex, bSuggSimil=false) {
    // returns feminine plural forms
    // we don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    let aSugg = new Set();
    for (let sMorph of _dAnalyses.gl_get(sFlex, [])) {
        if (!sMorph.includes(":V")) {
            // not a verb
            if (sMorph.includes(":f") || sMorph.includes(":e")) {
                aSugg.add(suggPlur(sFlex));
            } else {
                let sStem = cregex.getLemmaOfMorph(sMorph);
                if (mfsp.isFemForm(sStem)) {
................................................................................
    if (aSugg.size > 0) {
        return Array.from(aSugg).join("|");
    }
    return "";
}

function hasFemForm (sFlex) {
    for (let sStem of stem(sFlex)) {
        if (mfsp.isFemForm(sStem) || conj.hasConj(sStem, ":PQ", ":Q3")) {
            return true;
        }
    }
    if (phonet.hasSimil(sFlex, ":f")) {
        return true;
    }
    return false;
}

function hasMasForm (sFlex) {
    for (let sStem of stem(sFlex)) {
        if (mfsp.isFemForm(sStem) || conj.hasConj(sStem, ":PQ", ":Q1")) {
            // what has a feminine form also has a masculine form
            return true;
        }
    }
    if (phonet.hasSimil(sFlex, ":m")) {
        return true;
    }
    return false;
}

function switchGender (sFlex, bPlur=null) {
    // we don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    let aSugg = new Set();
    if (bPlur === null) {
        for (let sMorph of _dAnalyses.gl_get(sFlex, [])) {
            if (sMorph.includes(":f")) {
                if (sMorph.includes(":s")) {
                    aSugg.add(suggMasSing(sFlex));
                } else if (sMorph.includes(":p")) {
                    aSugg.add(suggMasPlur(sFlex));
                }
            } else if (sMorph.includes(":m")) {
................................................................................
                } else {
                    aSugg.add(suggFemSing(sFlex));
                    aSugg.add(suggFemPlur(sFlex));
                }
            }
        }
    } else if (bPlur) {
        for (let sMorph of _dAnalyses.gl_get(sFlex, [])) {
            if (sMorph.includes(":f")) {
                aSugg.add(suggMasPlur(sFlex));
            } else if (sMorph.includes(":m")) {
                aSugg.add(suggFemPlur(sFlex));
            }
        }
    } else {
        for (let sMorph of _dAnalyses.gl_get(sFlex, [])) {
            if (sMorph.includes(":f")) {
                aSugg.add(suggMasSing(sFlex));
            } else if (sMorph.includes(":m")) {
                aSugg.add(suggFemSing(sFlex));
            }
        }
    }
................................................................................
        return Array.from(aSugg).join("|");
    }
    return "";
}

function switchPlural (sFlex) {
    let aSugg = new Set();
    for (let sMorph of _dAnalyses.gl_get(sFlex, [])) { // we don’t check if word exists in _dAnalyses, for it is assumed it has been done before
        if (sMorph.includes(":s")) {
            aSugg.add(suggPlur(sFlex));
        } else if (sMorph.includes(":p")) {
            aSugg.add(suggSing(sFlex));
        }
    }
    if (aSugg.size > 0) {
................................................................................
    return "";
}

function hasSimil (sWord, sPattern=null) {
    return phonet.hasSimil(sWord, sPattern);
}

function suggSimil (sWord, sPattern=null, bSubst=false) {
    // return list of words phonetically similar to sWord and whom POS is matching sPattern




    let aSugg = phonet.selectSimil(sWord, sPattern);
    for (let sMorph of _dAnalyses.gl_get(sWord, [])) {
        for (let e of conj.getSimil(sWord, sMorph, bSubst)) {
            aSugg.add(e);
        }
    }
    if (aSugg.size > 0) {



        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggCeOrCet (sWord) {
    if (/^[aeéèêiouyâîï]/i.test(sWord)) {
................................................................................
    if (sWord[0] == "h" || sWord[0] == "H") {
        return "ce|cet";
    }
    return "ce";
}

function suggLesLa (sWord) {
    // we don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    if (_dAnalyses.gl_get(sWord, []).some(s  =>  s.includes(":p"))) {
        return "les|la";
    }
    return "la";
}

function formatNumber (s) {
    let nLen = s.length;







>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
>
>
>
>

|




|

|







 







>
>
>







|







 







|










|
>
>
>
>

|







 







>
>
>






|







 







|







 







|
>


|







 







<

|







 







<

|







 







<

|







 







<

|







 







|











|












<


|







 







|







|







 







|







 







|

>
>
>
>

|





>
>
>







 







<
|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
..
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
...
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
...
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
...
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
...
281
282
283
284
285
286
287

288
289
290
291
292
293
294
295
296
...
316
317
318
319
320
321
322

323
324
325
326
327
328
329
330
331
...
356
357
358
359
360
361
362

363
364
365
366
367
368
369
370
371
...
389
390
391
392
393
394
395

396
397
398
399
400
401
402
403
404
...
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452

453
454
455
456
457
458
459
460
461
462
...
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
...
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
...
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
...
540
541
542
543
544
545
546

547
548
549
550
551
552
553
554
    var mfsp = require("resource://grammalecte/fr/mfsp.js");
    var phonet = require("resource://grammalecte/fr/phonet.js");
}


//// verbs

function splitVerb (sVerb) {
    // renvoie le verbe et les pronoms séparément
    let iRight = sVerb.lastIndexOf("-");
    let sSuffix = sVerb.slice(iRight);
    sVerb = sVerb.slice(0, iRight);
    if (sVerb.endsWith("-t") || sVerb.endsWith("-le") || sVerb.endsWith("-la") || sVerb.endsWith("-les")) {
        iRight = sVerb.lastIndexOf("-");
        sSuffix = sVerb.slice(iRight) + sSuffix;
        sVerb = sVerb.slice(0, iRight);
    }
    return [sVerb, sSuffix];
}

function suggVerb (sFlex, sWho, funcSugg2=null, bVC=false) {

    let sSfx;
    if (bVC) {
        [sFlex, sSfx] = splitVerb(sFlex);
    }
    let aSugg = new Set();
    for (let sStem of _oSpellChecker.getLemma(sFlex)) {
        let tTags = conj._getTags(sStem);
        if (tTags) {
            // we get the tense
            let aTense = new Set();
            for (let sMorph of _oSpellChecker.getMorph(sFlex)) {
                let m;
                let zVerb = new RegExp (">"+sStem+"/.*?(:(?:Y|I[pqsf]|S[pq]|K))", "g");
                while ((m = zVerb.exec(sMorph)) !== null) {
                    // stem must be used in regex to prevent confusion between different verbs (e.g. sauras has 2 stems: savoir and saurer)
                    if (m) {
                        if (m[1] === ":Y") {
                            aTense.add(":Ip");
                            aTense.add(":Iq");
                            aTense.add(":Is");
................................................................................
    if (funcSugg2) {
        let aSugg2 = funcSugg2(sFlex);
        if (aSugg2.size > 0) {
            aSugg.add(aSugg2);
        }
    }
    if (aSugg.size > 0) {
        if (bVC) {
            return Array.from(aSugg).map((sSugg) => { return sSugg + sSfx; }).join("|");
        }
        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggVerbPpas (sFlex, sWhat=null) {
    let aSugg = new Set();
    for (let sStem of _oSpellChecker.getLemma(sFlex)) {
        let tTags = conj._getTags(sStem);
        if (tTags) {
            if (!sWhat) {
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"));
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q2"));
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q3"));
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q4"));
................................................................................
        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggVerbTense (sFlex, sTense, sWho) {
    let aSugg = new Set();
    for (let sStem of _oSpellChecker.getLemma(sFlex)) {
        if (conj.hasConj(sStem, sTense, sWho)) {
            aSugg.add(conj.getConj(sStem, sTense, sWho));
        }
    }
    if (aSugg.size > 0) {
        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggVerbImpe (sFlex, bVC=false) {
    let sSfx;
    if (bVC) {
        [sFlex, sSfx] = splitVerb(sFlex);
    }
    let aSugg = new Set();
    for (let sStem of _oSpellChecker.getLemma(sFlex)) {
        let tTags = conj._getTags(sStem);
        if (tTags) {
            if (conj._hasConjWithTags(tTags, ":E", ":2s")) {
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":E", ":2s"));
            }
            if (conj._hasConjWithTags(tTags, ":E", ":1p")) {
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":E", ":1p"));
................................................................................
            }
            if (conj._hasConjWithTags(tTags, ":E", ":2p")) {
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":E", ":2p"));
            }
        }
    }
    if (aSugg.size > 0) {
        if (bVC) {
            return Array.from(aSugg).map((sSugg) => { return sSugg + sSfx; }).join("|");
        }
        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggVerbInfi (sFlex) {
    return _oSpellChecker.getLemma(sFlex).filter(sStem => conj.isVerb(sStem)).join("|");
}


const _dQuiEst = new Map ([
    ["je", ":1s"], ["j’", ":1s"], ["j’en", ":1s"], ["j’y", ":1s"],
    ["tu", ":2s"], ["il", ":3s"], ["on", ":3s"], ["elle", ":3s"],
    ["nous", ":1p"], ["vous", ":2p"], ["ils", ":3p"], ["elles", ":3p"]
................................................................................
    if (!sWho) {
        if (sSuj[0].gl_isLowerCase()) { // pas un pronom, ni un nom propre
            return "";
        }
        sWho = ":3s";
    }
    let aSugg = new Set();
    for (let sStem of _oSpellChecker.getLemma(sFlex)) {
        let tTags = conj._getTags(sStem);
        if (tTags) {
            for (let sTense of lMode) {
                if (conj._hasConjWithTags(tTags, sTense, sWho)) {
                    aSugg.add(conj._getConjWithTags(sStem, tTags, sTense, sWho));
                }
            }
................................................................................
}

//// Nouns and adjectives

function suggPlur (sFlex, sWordToAgree=null) {
    // returns plural forms assuming sFlex is singular
    if (sWordToAgree) {
        let lMorph = _oSpellChecker.getMorph(sWordToAgree);
        if (lMorph.length === 0) {
            return "";
        }
        let sGender = cregex.getGender(lMorph);
        if (sGender == ":m") {
            return suggMasPlur(sFlex);
        } else if (sGender == ":f") {
            return suggFemPlur(sFlex);
        }
    }
    let aSugg = new Set();
................................................................................
        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggMasSing (sFlex, bSuggSimil=false) {
    // returns masculine singular forms

    let aSugg = new Set();
    for (let sMorph of _oSpellChecker.getMorph(sFlex)) {
        if (!sMorph.includes(":V")) {
            // not a verb
            if (sMorph.includes(":m") || sMorph.includes(":e")) {
                aSugg.add(suggSing(sFlex));
            } else {
                let sStem = cregex.getLemmaOfMorph(sMorph);
                if (mfsp.isFemForm(sStem)) {
................................................................................
        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggMasPlur (sFlex, bSuggSimil=false) {
    // returns masculine plural forms

    let aSugg = new Set();
    for (let sMorph of _oSpellChecker.getMorph(sFlex)) {
        if (!sMorph.includes(":V")) {
            // not a verb
            if (sMorph.includes(":m") || sMorph.includes(":e")) {
                aSugg.add(suggPlur(sFlex));
            } else {
                let sStem = cregex.getLemmaOfMorph(sMorph);
                if (mfsp.isFemForm(sStem)) {
................................................................................
    }
    return "";
}


function suggFemSing (sFlex, bSuggSimil=false) {
    // returns feminine singular forms

    let aSugg = new Set();
    for (let sMorph of _oSpellChecker.getMorph(sFlex)) {
        if (!sMorph.includes(":V")) {
            // not a verb
            if (sMorph.includes(":f") || sMorph.includes(":e")) {
                aSugg.add(suggSing(sFlex));
            } else {
                let sStem = cregex.getLemmaOfMorph(sMorph);
                if (mfsp.isFemForm(sStem)) {
................................................................................
        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggFemPlur (sFlex, bSuggSimil=false) {
    // returns feminine plural forms

    let aSugg = new Set();
    for (let sMorph of _oSpellChecker.getMorph(sFlex)) {
        if (!sMorph.includes(":V")) {
            // not a verb
            if (sMorph.includes(":f") || sMorph.includes(":e")) {
                aSugg.add(suggPlur(sFlex));
            } else {
                let sStem = cregex.getLemmaOfMorph(sMorph);
                if (mfsp.isFemForm(sStem)) {
................................................................................
    if (aSugg.size > 0) {
        return Array.from(aSugg).join("|");
    }
    return "";
}

function hasFemForm (sFlex) {
    for (let sStem of _oSpellChecker.getLemma(sFlex)) {
        if (mfsp.isFemForm(sStem) || conj.hasConj(sStem, ":PQ", ":Q3")) {
            return true;
        }
    }
    if (phonet.hasSimil(sFlex, ":f")) {
        return true;
    }
    return false;
}

function hasMasForm (sFlex) {
    for (let sStem of _oSpellChecker.getLemma(sFlex)) {
        if (mfsp.isFemForm(sStem) || conj.hasConj(sStem, ":PQ", ":Q1")) {
            // what has a feminine form also has a masculine form
            return true;
        }
    }
    if (phonet.hasSimil(sFlex, ":m")) {
        return true;
    }
    return false;
}

function switchGender (sFlex, bPlur=null) {

    let aSugg = new Set();
    if (bPlur === null) {
        for (let sMorph of _oSpellChecker.getMorph(sFlex)) {
            if (sMorph.includes(":f")) {
                if (sMorph.includes(":s")) {
                    aSugg.add(suggMasSing(sFlex));
                } else if (sMorph.includes(":p")) {
                    aSugg.add(suggMasPlur(sFlex));
                }
            } else if (sMorph.includes(":m")) {
................................................................................
                } else {
                    aSugg.add(suggFemSing(sFlex));
                    aSugg.add(suggFemPlur(sFlex));
                }
            }
        }
    } else if (bPlur) {
        for (let sMorph of _oSpellChecker.getMorph(sFlex)) {
            if (sMorph.includes(":f")) {
                aSugg.add(suggMasPlur(sFlex));
            } else if (sMorph.includes(":m")) {
                aSugg.add(suggFemPlur(sFlex));
            }
        }
    } else {
        for (let sMorph of _oSpellChecker.getMorph(sFlex)) {
            if (sMorph.includes(":f")) {
                aSugg.add(suggMasSing(sFlex));
            } else if (sMorph.includes(":m")) {
                aSugg.add(suggFemSing(sFlex));
            }
        }
    }
................................................................................
        return Array.from(aSugg).join("|");
    }
    return "";
}

function switchPlural (sFlex) {
    let aSugg = new Set();
    for (let sMorph of _oSpellChecker.getMorph(sFlex)) {
        if (sMorph.includes(":s")) {
            aSugg.add(suggPlur(sFlex));
        } else if (sMorph.includes(":p")) {
            aSugg.add(suggSing(sFlex));
        }
    }
    if (aSugg.size > 0) {
................................................................................
    return "";
}

function hasSimil (sWord, sPattern=null) {
    return phonet.hasSimil(sWord, sPattern);
}

function suggSimil (sWord, sPattern=null, bSubst=false, bVC=false) {
    // return list of words phonetically similar to sWord and whom POS is matching sPattern
    let sSfx;
    if (bVC) {
        [sWord, sSfx] = splitVerb(sWord);
    }
    let aSugg = phonet.selectSimil(sWord, sPattern);
    for (let sMorph of _oSpellChecker.getMorph(sWord)) {
        for (let e of conj.getSimil(sWord, sMorph, bSubst)) {
            aSugg.add(e);
        }
    }
    if (aSugg.size > 0) {
        if (bVC) {
            return Array.from(aSugg).map((sSugg) => { return sSugg + sSfx; }).join("|");
        }
        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggCeOrCet (sWord) {
    if (/^[aeéèêiouyâîï]/i.test(sWord)) {
................................................................................
    if (sWord[0] == "h" || sWord[0] == "H") {
        return "ce|cet";
    }
    return "ce";
}

function suggLesLa (sWord) {

    if (_oSpellChecker.getMorph(sWord).some(s  =>  s.includes(":p"))) {
        return "les|la";
    }
    return "la";
}

function formatNumber (s) {
    let nLen = s.length;

Modified gc_lang/fr/modules-js/lexicographe.js from [823f277d47] to [8830593e2a].

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
...
211
212
213
214
215
216
217

218
219
220
221
222
223




224
225
226
227
228
229
230
...
241
242
243
244
245
246
247

248
249
250
251
252
253
254
255
256
257
258
...
261
262
263
264
265
266
267
268
269
270
271
272
273
274







275
276
277
278
279
280
281
...
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
    [':O2', [" 2ᵉ pers.,", "Pronom : 2ᵉ personne"]],
    [':O3', [" 3ᵉ pers.,", "Pronom : 3ᵉ personne"]],
    [':C', [" conjonction,", "Conjonction"]],
    [':Ĉ', [" conjonction (él.),", "Conjonction (élément)"]],
    [':Cc', [" conjonction de coordination,", "Conjonction de coordination"]],
    [':Cs', [" conjonction de subordination,", "Conjonction de subordination"]],
    [':Ĉs', [" conjonction de subordination (él.),", "Conjonction de subordination (élément)"]],
    
    [':Ñ', [" locution nominale (él.),", "Locution nominale (élément)"]],
    [':Â', [" locution adjectivale (él.),", "Locution adjectivale (élément)"]],
    [':Ṽ', [" locution verbale (él.),", "Locution verbale (élément)"]],
    [':Ŵ', [" locution adverbiale (él.),", "Locution adverbiale (élément)"]],
    [':Ŕ', [" locution prépositive (él.),", "Locution prépositive (élément)"]],
    [':Ĵ', [" locution interjective (él.),", "Locution interjective (élément)"]],

................................................................................

    ['en', " pronom adverbial"],
    ["m'en", " (me) pronom personnel objet + (en) pronom adverbial"],
    ["t'en", " (te) pronom personnel objet + (en) pronom adverbial"],
    ["s'en", " (se) pronom personnel objet + (en) pronom adverbial"]
]);

const _dSeparator = new Map([
    ['.', "point"],
    ['·', "point médian"],
    ['…', "points de suspension"],
    [':', "deux-points"],
    [';', "point-virgule"],
    [',', "virgule"],
    ['?', "point d’interrogation"],
................................................................................
    ['–', "tiret demi-cadratin"],
    ['«', "guillemet ouvrant (chevrons)"],
    ['»', "guillemet fermant (chevrons)"],
    ['“', "guillemet ouvrant double"],
    ['”', "guillemet fermant double"],
    ['‘', "guillemet ouvrant"],
    ['’', "guillemet fermant"],

    ['/', "signe de la division"],
    ['+', "signe de l’addition"],
    ['*', "signe de la multiplication"],
    ['=', "signe de l’égalité"],
    ['<', "inférieur à"],
    ['>', "supérieur à"],




]);


class Lexicographe {

    constructor (oSpellChecker, oTokenizer, oLocGraph) {
        this.oSpellChecker = oSpellChecker;
................................................................................
    getInfoForToken (oToken) {
        // Token: .sType, .sValue, .nStart, .nEnd
        // return a object {sType, sValue, aLabel}
        let m = null;
        try {
            switch (oToken.sType) {
                case 'SEPARATOR':

                    return {
                        sType: oToken.sType,
                        sValue: oToken.sValue,
                        aLabel: [_dSeparator.gl_get(oToken.sValue, "caractère indéterminé")]
                    };
                    break;
                case 'NUM':
                    return {
                        sType: oToken.sType,
                        sValue: oToken.sValue,
                        aLabel: ["nombre"]
................................................................................
                case 'LINK':
                    return {
                        sType: oToken.sType,
                        sValue: oToken.sValue.slice(0, 40) + "…",
                        aLabel: ["hyperlien"]
                    };
                    break;
                case 'ELPFX':
                    let sTemp = oToken.sValue.replace("’", "").replace("'", "").replace("`", "").toLowerCase();
                    return {
                        sType: oToken.sType,
                        sValue: oToken.sValue,
                        aLabel: [_dElidedPrefix.gl_get(sTemp, "préfixe élidé inconnu")]
                    };







                    break;
                case 'FOLDERUNIX':
                    return {
                        sType: oToken.sType,
                        sValue: oToken.sValue.slice(0, 40) + "…",
                        aLabel: ["dossier UNIX (et dérivés)"]
                    };
................................................................................
                case 'FOLDERWIN':
                    return {
                        sType: oToken.sType,
                        sValue: oToken.sValue.slice(0, 40) + "…",
                        aLabel: ["dossier Windows"]
                    };
                    break;
                case 'ACRONYM':
                    return {
                        sType: oToken.sType,
                        sValue: oToken.sValue,
                        aLabel: ["Sigle ou acronyme"]
                    };
                    break;
                case 'WORD':
................................................................................
        let aTokenList = this.getListOfTokens(sText.replace("'", "’").trim(), false);
        let iKey = 0;
        let aElem = [];
        do {
            let oToken = aTokenList[iKey];
            let sMorphLoc = '';
            let aTokenTempList = [oToken];
            if (oToken.sType == "WORD" || oToken.sType == "ELPFX"){
                let iKeyTree = iKey + 1;
                let oLocNode = this.oLocGraph[oToken.sValue.toLowerCase()];
                while (oLocNode) {
                    let oTokenNext = aTokenList[iKeyTree];
                    iKeyTree++;
                    if (oTokenNext) {
                        oLocNode = oLocNode[oTokenNext.sValue.toLowerCase()];







|







 







|







 







>






>
>
>
>







 







>



|







 







|






>
>
>
>
>
>
>







 







|







 







|







83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
...
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
...
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
...
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
    [':O2', [" 2ᵉ pers.,", "Pronom : 2ᵉ personne"]],
    [':O3', [" 3ᵉ pers.,", "Pronom : 3ᵉ personne"]],
    [':C', [" conjonction,", "Conjonction"]],
    [':Ĉ', [" conjonction (él.),", "Conjonction (élément)"]],
    [':Cc', [" conjonction de coordination,", "Conjonction de coordination"]],
    [':Cs', [" conjonction de subordination,", "Conjonction de subordination"]],
    [':Ĉs', [" conjonction de subordination (él.),", "Conjonction de subordination (élément)"]],

    [':Ñ', [" locution nominale (él.),", "Locution nominale (élément)"]],
    [':Â', [" locution adjectivale (él.),", "Locution adjectivale (élément)"]],
    [':Ṽ', [" locution verbale (él.),", "Locution verbale (élément)"]],
    [':Ŵ', [" locution adverbiale (él.),", "Locution adverbiale (élément)"]],
    [':Ŕ', [" locution prépositive (él.),", "Locution prépositive (élément)"]],
    [':Ĵ', [" locution interjective (él.),", "Locution interjective (élément)"]],

................................................................................

    ['en', " pronom adverbial"],
    ["m'en", " (me) pronom personnel objet + (en) pronom adverbial"],
    ["t'en", " (te) pronom personnel objet + (en) pronom adverbial"],
    ["s'en", " (se) pronom personnel objet + (en) pronom adverbial"]
]);

const _dChar = new Map([
    ['.', "point"],
    ['·', "point médian"],
    ['…', "points de suspension"],
    [':', "deux-points"],
    [';', "point-virgule"],
    [',', "virgule"],
    ['?', "point d’interrogation"],
................................................................................
    ['–', "tiret demi-cadratin"],
    ['«', "guillemet ouvrant (chevrons)"],
    ['»', "guillemet fermant (chevrons)"],
    ['“', "guillemet ouvrant double"],
    ['”', "guillemet fermant double"],
    ['‘', "guillemet ouvrant"],
    ['’', "guillemet fermant"],
    ['"', "guillemets droits (déconseillé en typographie)"],
    ['/', "signe de la division"],
    ['+', "signe de l’addition"],
    ['*', "signe de la multiplication"],
    ['=', "signe de l’égalité"],
    ['<', "inférieur à"],
    ['>', "supérieur à"],
    ['⩽', "inférieur ou égal à"],
    ['⩾', "supérieur ou égal à"],
    ['%', "signe de pourcentage"],
    ['‰', "signe pour mille"],
]);


class Lexicographe {

    constructor (oSpellChecker, oTokenizer, oLocGraph) {
        this.oSpellChecker = oSpellChecker;
................................................................................
    getInfoForToken (oToken) {
        // Token: .sType, .sValue, .nStart, .nEnd
        // return a object {sType, sValue, aLabel}
        let m = null;
        try {
            switch (oToken.sType) {
                case 'SEPARATOR':
                case 'SIGN':
                    return {
                        sType: oToken.sType,
                        sValue: oToken.sValue,
                        aLabel: [_dChar.gl_get(oToken.sValue, "caractère indéterminé")]
                    };
                    break;
                case 'NUM':
                    return {
                        sType: oToken.sType,
                        sValue: oToken.sValue,
                        aLabel: ["nombre"]
................................................................................
                case 'LINK':
                    return {
                        sType: oToken.sType,
                        sValue: oToken.sValue.slice(0, 40) + "…",
                        aLabel: ["hyperlien"]
                    };
                    break;
                case 'WORD_ELIDED':
                    let sTemp = oToken.sValue.replace("’", "").replace("'", "").replace("`", "").toLowerCase();
                    return {
                        sType: oToken.sType,
                        sValue: oToken.sValue,
                        aLabel: [_dElidedPrefix.gl_get(sTemp, "préfixe élidé inconnu")]
                    };
                    break;
                case 'WORD_ORDINAL':
                    return {
                        sType: oToken.sType,
                        sValue: oToken.sValue,
                        aLabel: ["nombre ordinal"]
                    };
                    break;
                case 'FOLDERUNIX':
                    return {
                        sType: oToken.sType,
                        sValue: oToken.sValue.slice(0, 40) + "…",
                        aLabel: ["dossier UNIX (et dérivés)"]
                    };
................................................................................
                case 'FOLDERWIN':
                    return {
                        sType: oToken.sType,
                        sValue: oToken.sValue.slice(0, 40) + "…",
                        aLabel: ["dossier Windows"]
                    };
                    break;
                case 'WORD_ACRONYM':
                    return {
                        sType: oToken.sType,
                        sValue: oToken.sValue,
                        aLabel: ["Sigle ou acronyme"]
                    };
                    break;
                case 'WORD':
................................................................................
        let aTokenList = this.getListOfTokens(sText.replace("'", "’").trim(), false);
        let iKey = 0;
        let aElem = [];
        do {
            let oToken = aTokenList[iKey];
            let sMorphLoc = '';
            let aTokenTempList = [oToken];
            if (oToken.sType == "WORD" || oToken.sType == "WORD_ELIDED"){
                let iKeyTree = iKey + 1;
                let oLocNode = this.oLocGraph[oToken.sValue.toLowerCase()];
                while (oLocNode) {
                    let oTokenNext = aTokenList[iKeyTree];
                    iKeyTree++;
                    if (oTokenNext) {
                        oLocNode = oLocNode[oTokenNext.sValue.toLowerCase()];

Modified gc_lang/fr/modules/conj.py from [c668aaf269] to [258383e97f].


1


2
3
4
5
6
7
8
..
25
26
27
28
29
30
31

32
33
34
35
36
37
38
..
52
53
54
55
56
57
58

59
60
61
62
63
64
65
66
67
68
..
96
97
98
99
100
101
102

103
104
105
106
107
108
109
...
138
139
140
141
142
143
144
145
146
147
148
149
150


151
152
153
154
155
156
157
...
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
...
287
288
289
290
291
292
293

294
295
296
297
298
299
300
...
309
310
311
312
313
314
315

316
317
318
319
320
321
322

323
324
325
326
327
328
329
...
346
347
348
349
350
351
352

353
354
355
356
357
358
359
...
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
...
400
401
402
403
404
405
406

407
408
409
410
411
412
413

# Grammalecte - Conjugueur


# License: GPL 3

import re
import traceback

from .conj_data import lVtyp as _lVtyp
from .conj_data import lTags as _lTags
................................................................................
_dGroup = { "0": "auxiliaire", "1": "1ᵉʳ groupe", "2": "2ᵉ groupe", "3": "3ᵉ groupe" }

_dTenseIdx = { ":PQ": 0, ":Ip": 1, ":Iq": 2, ":Is": 3, ":If": 4, ":K": 5, ":Sp": 6, ":Sq": 7, ":E": 8 }



def isVerb (sVerb):

    return sVerb in _dVerb


def getConj (sVerb, sTense, sWho):
    "returns conjugation (can be an empty string)"
    if sVerb not in _dVerb:
        return None
................................................................................
    "returns raw informations about sVerb"
    if sVerb not in _dVerb:
        return None
    return _lVtyp[_dVerb[sVerb][0]]


def getSimil (sWord, sMorph, bSubst=False):

    if ":V" not in sMorph:
        return set()
    sInfi = sMorph[1:sMorph.find(" ")]
    aSugg = set()
    tTags = _getTags(sInfi)
    if tTags:
        if not bSubst:
            # we suggest conjugated forms
            if ":V1" in sMorph:
                aSugg.add(sInfi)
................................................................................
            # if there is only one past participle (epi inv), unreliable.
            if len(aSugg) == 1:
                aSugg.clear()
    return aSugg


def getConjSimilInfiV1 (sInfi):

    if sInfi not in _dVerb:
        return set()
    aSugg = set()
    tTags = _getTags(sInfi)
    if tTags:
        aSugg.add(_getConjWithTags(sInfi, tTags, ":Iq", ":2s"))
        aSugg.add(_getConjWithTags(sInfi, tTags, ":Iq", ":3s"))
................................................................................
    "returns sWord modified by sSfx"
    if not sSfx:
        return ""
    if sSfx == "0":
        return sWord
    try:
        return sWord[:-(ord(sSfx[0])-48)] + sSfx[1:]  if sSfx[0] != '0'  else  sWord + sSfx[1:]  # 48 is the ASCII code for "0"
    except:
        return "## erreur, code : " + str(sSfx) + " ##"
        


class Verb ():


    def __init__ (self, sVerb, sVerbPattern=""):
        # conjugate a unknown verb with rules from sVerbPattern
        if not isinstance(sVerb, str):
            raise TypeError("sVerb should be a string")
        if not sVerb:
            raise ValueError("Empty string.")

................................................................................
        self._sRawInfo = getVtyp(sVerbPattern)
        self.sInfo = self._readableInfo()
        self.bProWithEn = (self._sRawInfo[5] == "e")
        self._tTags = _getTags(sVerbPattern)
        if not self._tTags:
            raise ValueError("Unknown verb.")
        self._tTagsAux = _getTags(self.sVerbAux)
        self.cGroup = self._sRawInfo[0];
        self.dConj = {
            ":Y": {
                "label": "Infinitif",
                ":": sVerb,
            },
            ":P": {
                "label": "Participe présent",
................................................................................
                sInfo = "# erreur - code : " + self._sRawInfo
            return sGroup + " · " + sInfo
        except:
            traceback.print_exc()
            return "# erreur"

    def infinitif (self, bPro, bNeg, bTpsCo, bInt, bFem):

        try:
            if bTpsCo:
                sInfi = self.sVerbAux  if not bPro  else  "être"
            else:
                sInfi = self.sVerb
            if bPro:
                if self.bProWithEn:
................................................................................
                sInfi += " … ?"
            return sInfi
        except:
            traceback.print_exc()
            return "# erreur"

    def participePasse (self, sWho):

        try:
            return self.dConj[":Q"][sWho]
        except:
            traceback.print_exc()
            return "# erreur"

    def participePresent (self, bPro, bNeg, bTpsCo, bInt, bFem):

        try:
            if not self.dConj[":P"][":"]:
                return ""
            if bTpsCo:
                sPartPre = _getConjWithTags(self.sVerbAux, self._tTagsAux, ":PQ", ":P")  if not bPro  else  getConj("être", ":PQ", ":P")
            else:
                sPartPre = self.dConj[":P"][":"]
................................................................................
                sPartPre += " … ?"
            return sPartPre
        except:
            traceback.print_exc()
            return "# erreur"

    def conjugue (self, sTemps, sWho, bPro, bNeg, bTpsCo, bInt, bFem):

        try:
            if not self.dConj[sTemps][sWho]:
                return ""
            if not bTpsCo and bInt and sWho == ":1s" and self.dConj[sTemps].get(":1ś", False):
                sWho = ":1ś"
            if bTpsCo:
                sConj = _getConjWithTags(self.sVerbAux, self._tTagsAux, sTemps, sWho)  if not bPro  else  getConj("être", sTemps, sWho)
................................................................................
                else:
                    sConj = _dProObjEl[sWho] + "en " + sConj
            if bNeg:
                sConj = "n’" + sConj  if bEli and not bPro  else  "ne " + sConj
            if bInt:
                if sWho == ":3s" and not _zNeedTeuph.search(sConj):
                    sConj += "-t"
                sConj += "-" + self._getPronom(sWho, bFem)
            else:
                if sWho == ":1s" and bEli and not bNeg and not bPro:
                    sConj = "j’" + sConj
                else:
                    sConj = self._getPronom(sWho, bFem) + " " + sConj
            if bNeg:
                sConj += " pas"
            if bTpsCo:
                sConj += " " + self._seekPpas(bPro, bFem, sWho.endswith("p") or self._sRawInfo[5] == "r")
            if bInt:
                sConj += " … ?"
            return sConj
        except:
            traceback.print_exc()
            return "# erreur"

    def _getPronom (self, sWho, bFem):
        try:
            if sWho == ":3s":
                if self._sRawInfo[5] == "r":
                    return "on"
                elif bFem:
                    return "elle"
            elif sWho == ":3p" and bFem:
................................................................................
                return "elles"
            return _dProSuj[sWho]
        except:
            traceback.print_exc()
            return "# erreur"

    def imperatif (self, sWho, bPro, bNeg, bTpsCo, bFem):

        try:
            if not self.dConj[":E"][sWho]:
                return ""
            if bTpsCo:
                sImpe = _getConjWithTags(self.sVerbAux, self._tTagsAux, ":E", sWho)  if not bPro  else  getConj(u"être", ":E", sWho)
            else:
                sImpe = self.dConj[":E"][sWho]
>
|
>
>







 







>







 







>


|







 







>







 







|

|



>
>







 







|







 







>







 







>







>







 







>







 







|




|











|







 







>







1
2
3
4
5
6
7
8
9
10
11
..
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
..
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
...
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
...
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
...
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
...
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
...
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
"""
Grammalecte - Conjugueur
"""

# License: GPL 3

import re
import traceback

from .conj_data import lVtyp as _lVtyp
from .conj_data import lTags as _lTags
................................................................................
_dGroup = { "0": "auxiliaire", "1": "1ᵉʳ groupe", "2": "2ᵉ groupe", "3": "3ᵉ groupe" }

_dTenseIdx = { ":PQ": 0, ":Ip": 1, ":Iq": 2, ":Is": 3, ":If": 4, ":K": 5, ":Sp": 6, ":Sq": 7, ":E": 8 }



def isVerb (sVerb):
    "return True if it’s a existing verb"
    return sVerb in _dVerb


def getConj (sVerb, sTense, sWho):
    "returns conjugation (can be an empty string)"
    if sVerb not in _dVerb:
        return None
................................................................................
    "returns raw informations about sVerb"
    if sVerb not in _dVerb:
        return None
    return _lVtyp[_dVerb[sVerb][0]]


def getSimil (sWord, sMorph, bSubst=False):
    "returns a set of verbal forms similar to <sWord>, according to <sMorph>"
    if ":V" not in sMorph:
        return set()
    sInfi = sMorph[1:sMorph.find("/")]
    aSugg = set()
    tTags = _getTags(sInfi)
    if tTags:
        if not bSubst:
            # we suggest conjugated forms
            if ":V1" in sMorph:
                aSugg.add(sInfi)
................................................................................
            # if there is only one past participle (epi inv), unreliable.
            if len(aSugg) == 1:
                aSugg.clear()
    return aSugg


def getConjSimilInfiV1 (sInfi):
    "returns verbal forms phonetically similar to infinitive form (for verb in group 1)"
    if sInfi not in _dVerb:
        return set()
    aSugg = set()
    tTags = _getTags(sInfi)
    if tTags:
        aSugg.add(_getConjWithTags(sInfi, tTags, ":Iq", ":2s"))
        aSugg.add(_getConjWithTags(sInfi, tTags, ":Iq", ":3s"))
................................................................................
    "returns sWord modified by sSfx"
    if not sSfx:
        return ""
    if sSfx == "0":
        return sWord
    try:
        return sWord[:-(ord(sSfx[0])-48)] + sSfx[1:]  if sSfx[0] != '0'  else  sWord + sSfx[1:]  # 48 is the ASCII code for "0"
    except (IndexError, TypeError):
        return "## erreur, code : " + str(sSfx) + " ##"



class Verb ():
    "Verb and its conjugation"

    def __init__ (self, sVerb, sVerbPattern=""):
        # conjugate a unknown verb with rules from sVerbPattern
        if not isinstance(sVerb, str):
            raise TypeError("sVerb should be a string")
        if not sVerb:
            raise ValueError("Empty string.")

................................................................................
        self._sRawInfo = getVtyp(sVerbPattern)
        self.sInfo = self._readableInfo()
        self.bProWithEn = (self._sRawInfo[5] == "e")
        self._tTags = _getTags(sVerbPattern)
        if not self._tTags:
            raise ValueError("Unknown verb.")
        self._tTagsAux = _getTags(self.sVerbAux)
        self.cGroup = self._sRawInfo[0]
        self.dConj = {
            ":Y": {
                "label": "Infinitif",
                ":": sVerb,
            },
            ":P": {
                "label": "Participe présent",
................................................................................
                sInfo = "# erreur - code : " + self._sRawInfo
            return sGroup + " · " + sInfo
        except:
            traceback.print_exc()
            return "# erreur"

    def infinitif (self, bPro, bNeg, bTpsCo, bInt, bFem):
        "returns string (conjugaison à l’infinitif)"
        try:
            if bTpsCo:
                sInfi = self.sVerbAux  if not bPro  else  "être"
            else:
                sInfi = self.sVerb
            if bPro:
                if self.bProWithEn:
................................................................................
                sInfi += " … ?"
            return sInfi
        except:
            traceback.print_exc()
            return "# erreur"

    def participePasse (self, sWho):
        "returns past participle according to <sWho>"
        try:
            return self.dConj[":Q"][sWho]
        except:
            traceback.print_exc()
            return "# erreur"

    def participePresent (self, bPro, bNeg, bTpsCo, bInt, bFem):
        "returns string (conjugaison du participe présent)"
        try:
            if not self.dConj[":P"][":"]:
                return ""
            if bTpsCo:
                sPartPre = _getConjWithTags(self.sVerbAux, self._tTagsAux, ":PQ", ":P")  if not bPro  else  getConj("être", ":PQ", ":P")
            else:
                sPartPre = self.dConj[":P"][":"]
................................................................................
                sPartPre += " … ?"
            return sPartPre
        except:
            traceback.print_exc()
            return "# erreur"

    def conjugue (self, sTemps, sWho, bPro, bNeg, bTpsCo, bInt, bFem):
        "returns string (conjugue le verbe au temps <sTemps> pour <sWho>) "
        try:
            if not self.dConj[sTemps][sWho]:
                return ""
            if not bTpsCo and bInt and sWho == ":1s" and self.dConj[sTemps].get(":1ś", False):
                sWho = ":1ś"
            if bTpsCo:
                sConj = _getConjWithTags(self.sVerbAux, self._tTagsAux, sTemps, sWho)  if not bPro  else  getConj("être", sTemps, sWho)
................................................................................
                else:
                    sConj = _dProObjEl[sWho] + "en " + sConj
            if bNeg:
                sConj = "n’" + sConj  if bEli and not bPro  else  "ne " + sConj
            if bInt:
                if sWho == ":3s" and not _zNeedTeuph.search(sConj):
                    sConj += "-t"
                sConj += "-" + self._getPronomSujet(sWho, bFem)
            else:
                if sWho == ":1s" and bEli and not bNeg and not bPro:
                    sConj = "j’" + sConj
                else:
                    sConj = self._getPronomSujet(sWho, bFem) + " " + sConj
            if bNeg:
                sConj += " pas"
            if bTpsCo:
                sConj += " " + self._seekPpas(bPro, bFem, sWho.endswith("p") or self._sRawInfo[5] == "r")
            if bInt:
                sConj += " … ?"
            return sConj
        except:
            traceback.print_exc()
            return "# erreur"

    def _getPronomSujet (self, sWho, bFem):
        try:
            if sWho == ":3s":
                if self._sRawInfo[5] == "r":
                    return "on"
                elif bFem:
                    return "elle"
            elif sWho == ":3p" and bFem:
................................................................................
                return "elles"
            return _dProSuj[sWho]
        except:
            traceback.print_exc()
            return "# erreur"

    def imperatif (self, sWho, bPro, bNeg, bTpsCo, bFem):
        "returns string (conjugaison à l’impératif)"
        try:
            if not self.dConj[":E"][sWho]:
                return ""
            if bTpsCo:
                sImpe = _getConjWithTags(self.sVerbAux, self._tTagsAux, ":E", sWho)  if not bPro  else  getConj(u"être", ":E", sWho)
            else:
                sImpe = self.dConj[":E"][sWho]

Modified gc_lang/fr/modules/conj_data.py from [9859567121] to [5beef9bf2b].

cannot compute difference between binary files

Modified gc_lang/fr/modules/conj_generator.py from [2e696a65e3] to [ee0a228497].


1
2

3
4
5
6
7

8
9
10
11
12
13
14
15
16
17

18
19
20
21
22
23
24
25
26
27
28
29
30

31
32
33
34
35
36
37
...
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

# Conjugation generator
# beta stage, unfinished, the root for a new way to generate flexions…


import re


def conjugate (sVerb, sVerbTag="i_____a", bVarPpas=True):

    lConj = []
    cGroup = getVerbGroupChar(sVerb)
    for nCut, sAdd, sFlexTags, sPattern in getConjRules(sVerb, bVarPpas):
        if not sPattern or re.search(sPattern, sVerb):
            sFlexion = sVerb[0:-nCut] + sAdd  if nCut  else sVerb + sAdd
            lConj.append((sFlexion, ":V" + cGroup + "_" + sVerbTag + sFlexTags))
    return lConj


def getVerbGroupChar (sVerb, ):

    sVerb = sVerb.lower()
    if sVerb.endswith("er"):
        return "1"
    if sVerb.endswith("ir"):
        return "2"
    if sVerb == "être" or sVerb == "avoir":
        return "0"
    if sVerb.endswith("re"):
        return "3"
    return "4"


def getConjRules (sVerb, bVarPpas=True, nGroup=2):

    if sVerb.endswith("er"):
        # premier groupe, conjugaison en fonction de la terminaison du lemme
        # 5 lettres
        if sVerb[-5:] in oConj["V1"]:
            lConj = list(oConj["V1"][sVerb[-5:]])
        # 4 lettres
        elif sVerb[-4:] in oConj["V1"]:
................................................................................
        [2,     "isses",        ":Sp:Sq:2s/*",      False],
        [2,     "isse",         ":Sp:3s/*",         False],
        [2,     "ît",           ":Sq:3s/*",         False],
        [2,     "is",           ":E:2s/*",          False],
        [2,     "issons",       ":E:1p/*",          False],
        [2,     "issez",        ":E:2p/*",          False]
    ],
    
    # premier groupe (bien plus irrégulier que prétendu)
    "V1": {
        # a
        # verbes en -er, -ger, -yer, -cer
        "er": [
            [2,      "er",        ":Y/*",               False],
            [2,      "ant",       ":P/*",               False],
>
|
|
>





>









|
>













>







 







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
"""
Conjugation generator
beta stage, unfinished, the root for a new way to generate flexions…
"""

import re


def conjugate (sVerb, sVerbTag="i_____a", bVarPpas=True):
    "conjugate <sVerb> and returns a list of tuples (conjugation form, tags)"
    lConj = []
    cGroup = getVerbGroupChar(sVerb)
    for nCut, sAdd, sFlexTags, sPattern in getConjRules(sVerb, bVarPpas):
        if not sPattern or re.search(sPattern, sVerb):
            sFlexion = sVerb[0:-nCut] + sAdd  if nCut  else sVerb + sAdd
            lConj.append((sFlexion, ":V" + cGroup + "_" + sVerbTag + sFlexTags))
    return lConj


def getVerbGroupChar (sVerb):
    "returns the group number of <sVerb> guessing on its ending"
    sVerb = sVerb.lower()
    if sVerb.endswith("er"):
        return "1"
    if sVerb.endswith("ir"):
        return "2"
    if sVerb == "être" or sVerb == "avoir":
        return "0"
    if sVerb.endswith("re"):
        return "3"
    return "4"


def getConjRules (sVerb, bVarPpas=True, nGroup=2):
    "returns a list of lists to conjugate a verb, guessing on its ending"
    if sVerb.endswith("er"):
        # premier groupe, conjugaison en fonction de la terminaison du lemme
        # 5 lettres
        if sVerb[-5:] in oConj["V1"]:
            lConj = list(oConj["V1"][sVerb[-5:]])
        # 4 lettres
        elif sVerb[-4:] in oConj["V1"]:
................................................................................
        [2,     "isses",        ":Sp:Sq:2s/*",      False],
        [2,     "isse",         ":Sp:3s/*",         False],
        [2,     "ît",           ":Sq:3s/*",         False],
        [2,     "is",           ":E:2s/*",          False],
        [2,     "issons",       ":E:1p/*",          False],
        [2,     "issez",        ":E:2p/*",          False]
    ],

    # premier groupe (bien plus irrégulier que prétendu)
    "V1": {
        # a
        # verbes en -er, -ger, -yer, -cer
        "er": [
            [2,      "er",        ":Y/*",               False],
            [2,      "ant",       ":P/*",               False],

Modified gc_lang/fr/modules/cregex.py from [a0df0d1397] to [4b9e99ff72].


1

2
3
4
5
6
7
8
9
10
11
12
13
..
76
77
78
79
80
81
82

83
84
85

86
87
88
89
90
91
92
..
95
96
97
98
99
100
101

102
103
104
105
106
107
108
...
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

134
135
136

137
138
139

140
141
142

143
144
145

146
147
148

149
150
151

152
153
154

155
156
157

158
159
160

161
162
163

164
165
166
167
168
169

170
171
172

173
174
175

176
177
178

179
180
181

182
183
184
185
186
187
188
189
190

191
192
193

194
195
196

197
198
199

200
201
202

203
204
205

206
207
208

209
210
211

212
213
214

215
216
217

218
219
220

221
222
223

224
225
226

# Grammalecte - Compiled regular expressions


import re

#### Lemme
Lemma = re.compile("^>(\w[\w-]*)")

#### Analyses
Gender = re.compile(":[mfe]")
Number = re.compile(":[spi]")

#### Nom et adjectif
NA = re.compile(":[NA]")
................................................................................
NPf = re.compile(":(?:M[12P]|T):f")
NPe = re.compile(":(?:M[12P]|T):e")


#### FONCTIONS

def getLemmaOfMorph (s):

    return Lemma.search(s).group(1)

def checkAgreement (l1, l2):

    # check number agreement
    if not mbInv(l1) and not mbInv(l2):
        if mbSg(l1) and not mbSg(l2):
            return False
        if mbPl(l1) and not mbPl(l2):
            return False
    # check gender agreement
................................................................................
    if mbMas(l1) and not mbMas(l2):
        return False
    if mbFem(l1) and not mbFem(l2):
        return False
    return True

def checkConjVerb (lMorph, sReqConj):

    return any(sReqConj in s  for s in lMorph)

def getGender (lMorph):
    "returns gender of word (':m', ':f', ':e' or empty string)."
    sGender = ""
    for sMorph in lMorph:
        m = Gender.search(sMorph)
................................................................................
                return ":e"
    return sGender

def getNumber (lMorph):
    "returns number of word (':s', ':p', ':i' or empty string)."
    sNumber = ""
    for sMorph in lMorph:
        m = Number.search(sWord)
        if m:
            if not sNumber:
                sNumber = m.group(0)
            elif sNumber != m.group(0):
                return ":i"
    return sNumber

# NOTE :  isWhat (lMorph)    returns True   if lMorph contains nothing else than What
#         mbWhat (lMorph)    returns True   if lMorph contains What at least once

## isXXX = it’s certain

def isNom (lMorph):

    return all(":N" in s  for s in lMorph)

def isNomNotAdj (lMorph):

    return all(NnotA.search(s)  for s in lMorph)

def isAdj (lMorph):

    return all(":A" in s  for s in lMorph)

def isNomAdj (lMorph):

    return all(NA.search(s)  for s in lMorph)

def isNomVconj (lMorph):

    return all(NVconj.search(s)  for s in lMorph)

def isInv (lMorph):

    return all(":i" in s  for s in lMorph)

def isSg (lMorph):

    return all(":s" in s  for s in lMorph)

def isPl (lMorph):

    return all(":p" in s  for s in lMorph)

def isEpi (lMorph):

    return all(":e" in s  for s in lMorph)

def isMas (lMorph):

    return all(":m" in s  for s in lMorph)

def isFem (lMorph):

    return all(":f" in s  for s in lMorph)


## mbXXX = MAYBE XXX

def mbNom (lMorph):

    return any(":N" in s  for s in lMorph)

def mbAdj (lMorph):

    return any(":A" in s  for s in lMorph)

def mbAdjNb (lMorph):

    return any(AD.search(s)  for s in lMorph)

def mbNomAdj (lMorph):

    return any(NA.search(s)  for s in lMorph)

def mbNomNotAdj (lMorph):

    b = False
    for s in lMorph:
        if ":A" in s:
            return False
        if ":N" in s:
            b = True
    return b

def mbPpasNomNotAdj (lMorph):

    return any(PNnotA.search(s)  for s in lMorph)

def mbVconj (lMorph):

    return any(Vconj.search(s)  for s in lMorph)

def mbVconj123 (lMorph):

    return any(Vconj123.search(s)  for s in lMorph)

def mbMG (lMorph):

    return any(":G" in s  for s in lMorph)

def mbInv (lMorph):

    return any(":i" in s  for s in lMorph)

def mbSg (lMorph):

    return any(":s" in s  for s in lMorph)

def mbPl (lMorph):

    return any(":p" in s  for s in lMorph)

def mbEpi (lMorph):

    return any(":e" in s  for s in lMorph)

def mbMas (lMorph):

    return any(":m" in s  for s in lMorph)

def mbFem (lMorph):

    return any(":f" in s  for s in lMorph)

def mbNpr (lMorph):

    return any(NP.search(s)  for s in lMorph)

def mbNprMasNotFem (lMorph):

    if any(NPf.search(s)  for s in lMorph):
        return False
    return any(NPm.search(s)  for s in lMorph)
>
|
>




|







 







>



>







 







>







 







|













>



>



>



>



>



>



>



>



>



>



>






>



>



>



>



>
|




|
|


>



>



>



>



>



>



>



>



>



>



>



>



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
..
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
..
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
"""
Grammalecte - Compiled regular expressions
"""

import re

#### Lemme
Lemma = re.compile(r"^>(\w[\w-]*)")

#### Analyses
Gender = re.compile(":[mfe]")
Number = re.compile(":[spi]")

#### Nom et adjectif
NA = re.compile(":[NA]")
................................................................................
NPf = re.compile(":(?:M[12P]|T):f")
NPe = re.compile(":(?:M[12P]|T):e")


#### FONCTIONS

def getLemmaOfMorph (s):
    "return lemma in morphology <s>"
    return Lemma.search(s).group(1)

def checkAgreement (l1, l2):
    "returns True if agreement in gender and number is possible between morphologies <l1> and <l2>"
    # check number agreement
    if not mbInv(l1) and not mbInv(l2):
        if mbSg(l1) and not mbSg(l2):
            return False
        if mbPl(l1) and not mbPl(l2):
            return False
    # check gender agreement
................................................................................
    if mbMas(l1) and not mbMas(l2):
        return False
    if mbFem(l1) and not mbFem(l2):
        return False
    return True

def checkConjVerb (lMorph, sReqConj):
    "returns True if <sReqConj> in <lMorph>"
    return any(sReqConj in s  for s in lMorph)

def getGender (lMorph):
    "returns gender of word (':m', ':f', ':e' or empty string)."
    sGender = ""
    for sMorph in lMorph:
        m = Gender.search(sMorph)
................................................................................
                return ":e"
    return sGender

def getNumber (lMorph):
    "returns number of word (':s', ':p', ':i' or empty string)."
    sNumber = ""
    for sMorph in lMorph:
        m = Number.search(sMorph)
        if m:
            if not sNumber:
                sNumber = m.group(0)
            elif sNumber != m.group(0):
                return ":i"
    return sNumber

# NOTE :  isWhat (lMorph)    returns True   if lMorph contains nothing else than What
#         mbWhat (lMorph)    returns True   if lMorph contains What at least once

## isXXX = it’s certain

def isNom (lMorph):
    "returns True if all morphologies are “nom”"
    return all(":N" in s  for s in lMorph)

def isNomNotAdj (lMorph):
    "returns True if all morphologies are “nom”, but not “adjectif”"
    return all(NnotA.search(s)  for s in lMorph)

def isAdj (lMorph):
    "returns True if all morphologies are “adjectif”"
    return all(":A" in s  for s in lMorph)

def isNomAdj (lMorph):
    "returns True if all morphologies are “nom” or “adjectif”"
    return all(NA.search(s)  for s in lMorph)

def isNomVconj (lMorph):
    "returns True if all morphologies are “nom” or “verbe conjugué”"
    return all(NVconj.search(s)  for s in lMorph)

def isInv (lMorph):
    "returns True if all morphologies are “invariable”"
    return all(":i" in s  for s in lMorph)

def isSg (lMorph):
    "returns True if all morphologies are “singulier”"
    return all(":s" in s  for s in lMorph)

def isPl (lMorph):
    "returns True if all morphologies are “pluriel”"
    return all(":p" in s  for s in lMorph)

def isEpi (lMorph):
    "returns True if all morphologies are “épicène”"
    return all(":e" in s  for s in lMorph)

def isMas (lMorph):
    "returns True if all morphologies are “masculin”"
    return all(":m" in s  for s in lMorph)

def isFem (lMorph):
    "returns True if all morphologies are “féminin”"
    return all(":f" in s  for s in lMorph)


## mbXXX = MAYBE XXX

def mbNom (lMorph):
    "returns True if one morphology is “nom”"
    return any(":N" in s  for s in lMorph)

def mbAdj (lMorph):
    "returns True if one morphology is “adjectif”"
    return any(":A" in s  for s in lMorph)

def mbAdjNb (lMorph):
    "returns True if one morphology is “adjectif” or “nombre”"
    return any(AD.search(s)  for s in lMorph)

def mbNomAdj (lMorph):
    "returns True if one morphology is “nom” or “adjectif”"
    return any(NA.search(s)  for s in lMorph)

def mbNomNotAdj (lMorph):
    "returns True if one morphology is “nom”, but not “adjectif”"
    bResult = False
    for s in lMorph:
        if ":A" in s:
            return False
        if ":N" in s:
            bResult = True
    return bResult

def mbPpasNomNotAdj (lMorph):
    "returns True if one morphology is “nom” or “participe passé”, but not “adjectif”"
    return any(PNnotA.search(s)  for s in lMorph)

def mbVconj (lMorph):
    "returns True if one morphology is “nom” or “verbe conjugué”"
    return any(Vconj.search(s)  for s in lMorph)

def mbVconj123 (lMorph):
    "returns True if one morphology is “nom” or “verbe conjugué” (but not “avoir” or “être”)"
    return any(Vconj123.search(s)  for s in lMorph)

def mbMG (lMorph):
    "returns True if one morphology is “mot grammatical”"
    return any(":G" in s  for s in lMorph)

def mbInv (lMorph):
    "returns True if one morphology is “invariable”"
    return any(":i" in s  for s in lMorph)

def mbSg (lMorph):
    "returns True if one morphology is “singulier”"
    return any(":s" in s  for s in lMorph)

def mbPl (lMorph):
    "returns True if one morphology is “pluriel”"
    return any(":p" in s  for s in lMorph)

def mbEpi (lMorph):
    "returns True if one morphology is “épicène”"
    return any(":e" in s  for s in lMorph)

def mbMas (lMorph):
    "returns True if one morphology is “masculin”"
    return any(":m" in s  for s in lMorph)

def mbFem (lMorph):
    "returns True if one morphology is “féminin”"
    return any(":f" in s  for s in lMorph)

def mbNpr (lMorph):
    "returns True if one morphology is “nom propre” or “titre de civilité”"
    return any(NP.search(s)  for s in lMorph)

def mbNprMasNotFem (lMorph):
    "returns True if one morphology is “nom propre masculin” but not “féminin”"
    if any(NPf.search(s)  for s in lMorph):
        return False
    return any(NPm.search(s)  for s in lMorph)

Modified gc_lang/fr/modules/gce_analyseur.py from [39975de0ac] to [252fe3713f].

1
2
3
4
5







6
7

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
..
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#### GRAMMAR CHECKING ENGINE PLUGIN: Parsing functions for French language

from . import cregex as cr









def rewriteSubject (s1, s2):
    # s1 is supposed to be prn/patr/npr (M[12P])

    if s2 == "lui":
        return "ils"
    if s2 == "moi":
        return "nous"
    if s2 == "toi":
        return "vous"
    if s2 == "nous":
        return "nous"
    if s2 == "vous":
        return "vous"
    if s2 == "eux":
        return "ils"
    if s2 == "elle" or s2 == "elles":
        # We don’t check if word exists in _dAnalyses, for it is assumed it has been done before
        if cr.mbNprMasNotFem(_dAnalyses.get(s1, False)):
            return "ils"
        # si épicène, indéterminable, mais OSEF, le féminin l’emporte
        return "elles"
    return s1 + " et " + s2


def apposition (sWord1, sWord2):
    "returns True if nom + nom (no agreement required)"
    # We don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    return cr.mbNomNotAdj(_dAnalyses.get(sWord2, False)) and cr.mbPpasNomNotAdj(_dAnalyses.get(sWord1, False))


def isAmbiguousNAV (sWord):
    "words which are nom|adj and verb are ambiguous (except être and avoir)"
    if sWord not in _dAnalyses and not _storeMorphFromFSA(sWord):
        return False
    if not cr.mbNomAdj(_dAnalyses[sWord]) or sWord == "est":
        return False
    if cr.mbVconj(_dAnalyses[sWord]) and not cr.mbMG(_dAnalyses[sWord]):

        return True
    return False


def isAmbiguousAndWrong (sWord1, sWord2, sReqMorphNA, sReqMorphConj):
    "use it if sWord1 won’t be a verb; word2 is assumed to be True via isAmbiguousNAV"
    # We don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    a2 = _dAnalyses.get(sWord2, None)
    if not a2:
        return False
    if cr.checkConjVerb(a2, sReqMorphConj):
        # verb word2 is ok
        return False
    a1 = _dAnalyses.get(sWord1, None)
    if not a1:
        return False
    if cr.checkAgreement(a1, a2) and (cr.mbAdj(a2) or cr.mbAdj(a1)):
        return False
    return True


def isVeryAmbiguousAndWrong (sWord1, sWord2, sReqMorphNA, sReqMorphConj, bLastHopeCond):
    "use it if sWord1 can be also a verb; word2 is assumed to be True via isAmbiguousNAV"
    # We don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    a2 = _dAnalyses.get(sWord2, None)
    if not a2:
        return False
    if cr.checkConjVerb(a2, sReqMorphConj):
        # verb word2 is ok
        return False
    a1 = _dAnalyses.get(sWord1, None)
    if not a1:
        return False
    if cr.checkAgreement(a1, a2) and (cr.mbAdj(a2) or cr.mbAdjNb(a1)):
        return False
    # now, we know there no agreement, and conjugation is also wrong
    if cr.isNomAdj(a1):
        return True
................................................................................
    #if cr.isNomAdjVerb(a1): # considered True
    if bLastHopeCond:
        return True
    return False


def checkAgreement (sWord1, sWord2):
    # We don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    a2 = _dAnalyses.get(sWord2, None)
    if not a2:
        return True
    a1 = _dAnalyses.get(sWord1, None)
    if not a1:
        return True
    return cr.checkAgreement(a1, a2)


_zUnitSpecial = re.compile("[µ/⁰¹²³⁴⁵⁶⁷⁸⁹Ωℓ·]")
_zUnitNumbers = re.compile("[0-9]")

def mbUnit (s):

    if _zUnitSpecial.search(s):
        return True
    if 1 < len(s) < 16 and s[0:1].islower() and (not s[1:].islower() or _zUnitNumbers.search(s)):
        return True
    return False


#### Syntagmes

_zEndOfNG1 = re.compile(" *$| +(?:, +|)(?:n(?:’|e |o(?:u?s|tre) )|l(?:’|e(?:urs?|s|) |a )|j(?:’|e )|m(?:’|es? |a |on )|t(?:’|es? |a |u )|s(?:’|es? |a )|c(?:’|e(?:t|tte|s|) )|ç(?:a |’)|ils? |vo(?:u?s|tre) )")
_zEndOfNG2 = re.compile(r" +(\w[\w-]+)")
_zEndOfNG3 = re.compile(r" *, +(\w[\w-]+)")

def isEndOfNG (dDA, s, iOffset):
    if _zEndOfNG1.match(s):
        return True
    m = _zEndOfNG2.match(s)
    if m and morphex(dDA, (iOffset+m.start(1), m.group(1)), ":[VR]", ":[NAQP]"):
        return True
    m = _zEndOfNG3.match(s)
    if m and not morph(dDA, (iOffset+m.start(1), m.group(1)), ":[NA]", False):
        return True
    return False


_zNextIsNotCOD1 = re.compile(" *,")
_zNextIsNotCOD2 = re.compile(" +(?:[mtsnj](e +|’)|[nv]ous |tu |ils? |elles? )")
_zNextIsNotCOD3 = re.compile(r" +([a-zéèî][\w-]+)")

def isNextNotCOD (dDA, s, iOffset):
    if _zNextIsNotCOD1.match(s) or _zNextIsNotCOD2.match(s):
        return True
    m = _zNextIsNotCOD3.match(s)
    if m and morphex(dDA, (iOffset+m.start(1), m.group(1)), ":[123][sp]", ":[DM]"):
        return True
    return False


_zNextIsVerb1 = re.compile(" +[nmts](?:e |’)")
_zNextIsVerb2 = re.compile(r" +(\w[\w-]+)")

def isNextVerb (dDA, s, iOffset):
    if _zNextIsVerb1.match(s):
        return True
    m = _zNextIsVerb2.match(s)
    if m and morph(dDA, (iOffset+m.start(1), m.group(1)), ":[123][sp]", False):
        return True
    return False


#### Exceptions

aREGULARPLURAL = frozenset(["abricot", "amarante", "aubergine", "acajou", "anthracite", "brique", "caca", "café", \
                            "carotte", "cerise", "chataigne", "corail", "citron", "crème", "grave", "groseille", \
                            "jonquille", "marron", "olive", "pervenche", "prune", "sable"])
aSHOULDBEVERB = frozenset(["aller", "manger"]) 





>
>
>
>
>
>
>

<
>













<
|








|
<




|
<
|

<
>





|
|
<





|








|
|
<





|







 







|
|


|









>






<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






|
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27

28
29
30
31
32
33
34
35
36
37

38
39
40
41
42

43
44

45
46
47
48
49
50
51
52

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

69
70
71
72
73
74
75
76
77
78
79
80
81
..
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109











































110
111
112
113
114
115
116
#### GRAMMAR CHECKING ENGINE PLUGIN: Parsing functions for French language

from . import cregex as cr


def g_morphVC (dToken, sPattern, sNegPattern=""):
    nEnd = dToken["sValue"].rfind("-")
    if "-t-" in dToken["sValue"]:
        nEnd = nEnd - 2
    return g_morph(dToken, sPattern, sNegPattern, 0, nEnd, False)


def rewriteSubject (s1, s2):

    "rewrite complex subject: <s1> a prn/patr/npr (M[12P]) followed by “et” and <s2>"
    if s2 == "lui":
        return "ils"
    if s2 == "moi":
        return "nous"
    if s2 == "toi":
        return "vous"
    if s2 == "nous":
        return "nous"
    if s2 == "vous":
        return "vous"
    if s2 == "eux":
        return "ils"
    if s2 == "elle" or s2 == "elles":

        if cr.mbNprMasNotFem(_oSpellChecker.getMorph(s1)):
            return "ils"
        # si épicène, indéterminable, mais OSEF, le féminin l’emporte
        return "elles"
    return s1 + " et " + s2


def apposition (sWord1, sWord2):
    "returns True if nom + nom (no agreement required)"
    return len(sWord2) < 2 or (cr.mbNomNotAdj(_oSpellChecker.getMorph(sWord2)) and cr.mbPpasNomNotAdj(_oSpellChecker.getMorph(sWord1)))



def isAmbiguousNAV (sWord):
    "words which are nom|adj and verb are ambiguous (except être and avoir)"
    lMorph = _oSpellChecker.getMorph(sWord)

    if not cr.mbNomAdj(lMorph) or sWord == "est":
        return False

    if cr.mbVconj(lMorph) and not cr.mbMG(lMorph):
        return True
    return False


def isAmbiguousAndWrong (sWord1, sWord2, sReqMorphNA, sReqMorphConj):
    "use it if <sWord1> won’t be a verb; <sWord2> is assumed to be True via isAmbiguousNAV"
    a2 = _oSpellChecker.getMorph(sWord2)

    if not a2:
        return False
    if cr.checkConjVerb(a2, sReqMorphConj):
        # verb word2 is ok
        return False
    a1 = _oSpellChecker.getMorph(sWord1)
    if not a1:
        return False
    if cr.checkAgreement(a1, a2) and (cr.mbAdj(a2) or cr.mbAdj(a1)):
        return False
    return True


def isVeryAmbiguousAndWrong (sWord1, sWord2, sReqMorphNA, sReqMorphConj, bLastHopeCond):
    "use it if <sWord1> can be also a verb; <sWord2> is assumed to be True via isAmbiguousNAV"
    a2 = _oSpellChecker.getMorph(sWord2)

    if not a2:
        return False
    if cr.checkConjVerb(a2, sReqMorphConj):
        # verb word2 is ok
        return False
    a1 = _oSpellChecker.getMorph(sWord1)
    if not a1:
        return False
    if cr.checkAgreement(a1, a2) and (cr.mbAdj(a2) or cr.mbAdjNb(a1)):
        return False
    # now, we know there no agreement, and conjugation is also wrong
    if cr.isNomAdj(a1):
        return True
................................................................................
    #if cr.isNomAdjVerb(a1): # considered True
    if bLastHopeCond:
        return True
    return False


def checkAgreement (sWord1, sWord2):
    "check agreement between <sWord1> and <sWord1>"
    a2 = _oSpellChecker.getMorph(sWord2)
    if not a2:
        return True
    a1 = _oSpellChecker.getMorph(sWord1)
    if not a1:
        return True
    return cr.checkAgreement(a1, a2)


_zUnitSpecial = re.compile("[µ/⁰¹²³⁴⁵⁶⁷⁸⁹Ωℓ·]")
_zUnitNumbers = re.compile("[0-9]")

def mbUnit (s):
    "returns True it can be a measurement unit"
    if _zUnitSpecial.search(s):
        return True
    if 1 < len(s) < 16 and s[0:1].islower() and (not s[1:].islower() or _zUnitNumbers.search(s)):
        return True
    return False













































#### Exceptions

aREGULARPLURAL = frozenset(["abricot", "amarante", "aubergine", "acajou", "anthracite", "brique", "caca", "café", \
                            "carotte", "cerise", "chataigne", "corail", "citron", "crème", "grave", "groseille", \
                            "jonquille", "marron", "olive", "pervenche", "prune", "sable"])
aSHOULDBEVERB = frozenset(["aller", "manger"])

Modified gc_lang/fr/modules/gce_date_verif.py from [1265100649] to [c3f0a9eb2f].

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

38
39
40

41
42
43
44
45
46
47
48
49
50
51
52
53

_lDay = ["lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche"]
_dMonth = { "janvier":1, "février":2, "mars":3, "avril":4, "mai":5, "juin":6, "juillet":7, "août":8, "aout":8, "septembre":9, "octobre":10, "novembre":11, "décembre":12 }

import datetime


def checkDate (day, month, year):
    "to use if month is a number"
    try:
        return datetime.date(int(year), int(month), int(day))
    except ValueError:
        return False
    except:
        return True


def checkDateWithString (day, month, year):
    "to use if month is a noun"
    try:
        return datetime.date(int(year), _dMonth.get(month.lower(), ""), int(day))
    except ValueError:
        return False
    except:
        return True


def checkDay (weekday, day, month, year):
    "to use if month is a number"
    oDate = checkDate(day, month, year)
    if oDate and _lDay[oDate.weekday()] != weekday.lower():
        return False
    return True


def checkDayWithString (weekday, day, month, year):
    "to use if month is a noun"
    oDate = checkDate(day, _dMonth.get(month, ""), year)

    if oDate and _lDay[oDate.weekday()] != weekday.lower():
        return False
    return True


def getDay (day, month, year):
    "to use if month is a number"
    return _lDay[datetime.date(int(year), int(month), int(day)).weekday()]


def getDayWithString (day, month, year):
    "to use if month is a noun"
    return _lDay[datetime.date(int(year), _dMonth.get(month.lower(), ""), int(day)).weekday()]







|
|

|






|
|

|






|
|
|
|



>
|
|
<
>
|




|
|
|


|
|
|
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

41
42
43
44
45
46
47
48
49
50
51
52
53
54

_lDay = ["lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche"]
_dMonth = { "janvier":1, "février":2, "mars":3, "avril":4, "mai":5, "juin":6, "juillet":7, "août":8, "aout":8, "septembre":9, "octobre":10, "novembre":11, "décembre":12 }

import datetime


def checkDate (sDay, sMonth, sYear):
    "to use if <sMonth> is a number"
    try:
        return datetime.date(int(sYear), int(sMonth), int(sDay))
    except ValueError:
        return False
    except:
        return True


def checkDateWithString (sDay, sMonth, sYear):
    "to use if <sMonth> is a noun"
    try:
        return datetime.date(int(sYear), _dMonth.get(sMonth.lower(), ""), int(sDay))
    except ValueError:
        return False
    except:
        return True


def checkDay (sWeekday, sDay, sMonth, sYear):
    "to use if <sMonth> is a number"
    oDate = checkDate(sDay, sMonth, sYear)
    if oDate and _lDay[oDate.weekday()] != sWeekday.lower():
        return False
    return True


def checkDayWithString (sWeekday, sDay, sMonth, sYear):
    "to use if <sMonth> is a noun"

    oDate = checkDate(sDay, _dMonth.get(sMonth, ""), sYear)
    if oDate and _lDay[oDate.weekday()] != sWeekday.lower():
        return False
    return True


def getDay (sDay, sMonth, sYear):
    "to use if <sMonth> is a number"
    return _lDay[datetime.date(int(sYear), int(sMonth), int(sDay)).weekday()]


def getDayWithString (sDay, sMonth, sYear):
    "to use if <sMonth> is a noun"
    return _lDay[datetime.date(int(sYear), _dMonth.get(sMonth.lower(), ""), int(sDay)).weekday()]

Modified gc_lang/fr/modules/gce_suggestions.py from [79835965e4] to [00833488a6].

3
4
5
6
7
8
9












10



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
..
32
33
34
35
36
37
38


39
40
41
42
43

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

87
88
89
90
91
92
93
94
95
96



97
98
99
100
101
102
103
104
105
106
107


108
109
110
111
112

113
114
115
116
117
118
119
120
121

122
123
124
125
126
127
128
...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
...
145
146
147
148
149
150
151
152

153
154
155
156
157
158
159
160
161
...
189
190
191
192
193
194
195
196
197
198

199
200
201
202
203
204
205
...
217
218
219
220
221
222
223
224
225
226

227
228
229
230
231
232
233
...
248
249
250
251
252
253
254
255
256
257

258
259
260
261
262
263
264
...
274
275
276
277
278
279
280
281
282
283

284
285
286
287
288
289
290
...
299
300
301
302
303
304
305

306
307
308
309
310
311
312
313
314

315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
...
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372

373
374
375
376
377
378

379
380

381
382
383


384
385
386
387
388

389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405

406
407
408
409
410
411
412
...
433
434
435
436
437
438
439

440
441
442
443
444
445
446
447
448
449
450

451
452
453
454
455
456
457
...
468
469
470
471
472
473
474
475
476
477
478

479
from . import conj
from . import mfsp
from . import phonet


## Verbs













def suggVerb (sFlex, sWho, funcSugg2=None):



    aSugg = set()
    for sStem in stem(sFlex):
        tTags = conj._getTags(sStem)
        if tTags:
            # we get the tense
            aTense = set()
            for sMorph in _dAnalyses.get(sFlex, []): # we don’t check if word exists in _dAnalyses, for it is assumed it has been done before
                for m in re.finditer(">"+sStem+" .*?(:(?:Y|I[pqsf]|S[pq]|K|P))", sMorph):
                    # stem must be used in regex to prevent confusion between different verbs (e.g. sauras has 2 stems: savoir and saurer)
                    if m:
                        if m.group(1) == ":Y":
                            aTense.add(":Ip")
                            aTense.add(":Iq")
                            aTense.add(":Is")
                        elif m.group(1) == ":P":
................................................................................
                if conj._hasConjWithTags(tTags, sTense, sWho):
                    aSugg.add(conj._getConjWithTags(sStem, tTags, sTense, sWho))
    if funcSugg2:
        aSugg2 = funcSugg2(sFlex)
        if aSugg2:
            aSugg.add(aSugg2)
    if aSugg:


        return "|".join(aSugg)
    return ""


def suggVerbPpas (sFlex, sWhat=None):

    aSugg = set()
    for sStem in stem(sFlex):
        tTags = conj._getTags(sStem)
        if tTags:
            if not sWhat:
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"))
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q2"))
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q3"))
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q4"))
                aSugg.discard("")
            elif sWhat == ":m:s":
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"))
            elif sWhat == ":m:p":
                if conj._hasConjWithTags(tTags, ":PQ", ":Q2"):
                    aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q2"))
                else:
                    aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"))
            elif sWhat == ":f:s":
                if conj._hasConjWithTags(tTags, ":PQ", ":Q3"):
                    aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q3"))
                else:
                    aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"))
            elif sWhat == ":f:p":
                if conj._hasConjWithTags(tTags, ":PQ", ":Q4"):
                    aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q4"))
                else:
                    aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"))
            elif sWhat == ":s":
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"))
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q3"))
                aSugg.discard("")
            elif sWhat == ":p":
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q2"))
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q4"))
                aSugg.discard("")
            else:
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"))
    if aSugg:
        return "|".join(aSugg)
    return ""


def suggVerbTense (sFlex, sTense, sWho):

    aSugg = set()
    for sStem in stem(sFlex):
        if conj.hasConj(sStem, sTense, sWho):
            aSugg.add(conj.getConj(sStem, sTense, sWho))
    if aSugg:
        return "|".join(aSugg)
    return ""


def suggVerbImpe (sFlex):



    aSugg = set()
    for sStem in stem(sFlex):
        tTags = conj._getTags(sStem)
        if tTags:
            if conj._hasConjWithTags(tTags, ":E", ":2s"):
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":E", ":2s"))
            if conj._hasConjWithTags(tTags, ":E", ":1p"):
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":E", ":1p"))
            if conj._hasConjWithTags(tTags, ":E", ":2p"):
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":E", ":2p"))
    if aSugg:


        return "|".join(aSugg)
    return ""


def suggVerbInfi (sFlex):

    return "|".join([ sStem  for sStem in stem(sFlex)  if conj.isVerb(sStem) ])


_dQuiEst = { "je": ":1s", "j’": ":1s", "j’en": ":1s", "j’y": ":1s", \
             "tu": ":2s", "il": ":3s", "on": ":3s", "elle": ":3s", "nous": ":1p", "vous": ":2p", "ils": ":3p", "elles": ":3p" }
_lIndicatif = [":Ip", ":Iq", ":Is", ":If"]
_lSubjonctif = [":Sp", ":Sq"]

def suggVerbMode (sFlex, cMode, sSuj):

    if cMode == ":I":
        lMode = _lIndicatif
    elif cMode == ":S":
        lMode = _lSubjonctif
    elif cMode.startswith((":I", ":S")):
        lMode = [cMode]
    else:
................................................................................
        return ""
    sWho = _dQuiEst.get(sSuj.lower(), None)
    if not sWho:
        if sSuj[0:1].islower(): # pas un pronom, ni un nom propre
            return ""
        sWho = ":3s"
    aSugg = set()
    for sStem in stem(sFlex):
        tTags = conj._getTags(sStem)
        if tTags:
            for sTense in lMode:
                if conj._hasConjWithTags(tTags, sTense, sWho):
                    aSugg.add(conj._getConjWithTags(sStem, tTags, sTense, sWho))
    if aSugg:
        return "|".join(aSugg)
................................................................................


## Nouns and adjectives

def suggPlur (sFlex, sWordToAgree=None):
    "returns plural forms assuming sFlex is singular"
    if sWordToAgree:
        if sWordToAgree not in _dAnalyses and not _storeMorphFromFSA(sWordToAgree):

            return ""
        sGender = cr.getGender(_dAnalyses.get(sWordToAgree, []))
        if sGender == ":m":
            return suggMasPlur(sFlex)
        elif sGender == ":f":
            return suggFemPlur(sFlex)
    aSugg = set()
    if "-" not in sFlex:
        if sFlex.endswith("l"):
................................................................................
    if aSugg:
        return "|".join(aSugg)
    return ""


def suggMasSing (sFlex, bSuggSimil=False):
    "returns masculine singular forms"
    # we don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    aSugg = set()
    for sMorph in _dAnalyses.get(sFlex, []):

        if not ":V" in sMorph:
            # not a verb
            if ":m" in sMorph or ":e" in sMorph:
                aSugg.add(suggSing(sFlex))
            else:
                sStem = cr.getLemmaOfMorph(sMorph)
                if mfsp.isFemForm(sStem):
................................................................................
    if aSugg:
        return "|".join(aSugg)
    return ""


def suggMasPlur (sFlex, bSuggSimil=False):
    "returns masculine plural forms"
    # we don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    aSugg = set()
    for sMorph in _dAnalyses.get(sFlex, []):

        if not ":V" in sMorph:
            # not a verb
            if ":m" in sMorph or ":e" in sMorph:
                aSugg.add(suggPlur(sFlex))
            else:
                sStem = cr.getLemmaOfMorph(sMorph)
                if mfsp.isFemForm(sStem):
................................................................................
    if aSugg:
        return "|".join(aSugg)
    return ""


def suggFemSing (sFlex, bSuggSimil=False):
    "returns feminine singular forms"
    # we don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    aSugg = set()
    for sMorph in _dAnalyses.get(sFlex, []):

        if not ":V" in sMorph:
            # not a verb
            if ":f" in sMorph or ":e" in sMorph:
                aSugg.add(suggSing(sFlex))
            else:
                sStem = cr.getLemmaOfMorph(sMorph)
                if mfsp.isFemForm(sStem):
................................................................................
    if aSugg:
        return "|".join(aSugg)
    return ""


def suggFemPlur (sFlex, bSuggSimil=False):
    "returns feminine plural forms"
    # we don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    aSugg = set()
    for sMorph in _dAnalyses.get(sFlex, []):

        if not ":V" in sMorph:
            # not a verb
            if ":f" in sMorph or ":e" in sMorph:
                aSugg.add(suggPlur(sFlex))
            else:
                sStem = cr.getLemmaOfMorph(sMorph)
                if mfsp.isFemForm(sStem):
................................................................................
            aSugg.add(e)
    if aSugg:
        return "|".join(aSugg)
    return ""


def hasFemForm (sFlex):

    for sStem in stem(sFlex):
        if mfsp.isFemForm(sStem) or conj.hasConj(sStem, ":PQ", ":Q3"):
            return True
    if phonet.hasSimil(sFlex, ":f"):
        return True
    return False


def hasMasForm (sFlex):

    for sStem in stem(sFlex):
        if mfsp.isFemForm(sStem) or conj.hasConj(sStem, ":PQ", ":Q1"):
            # what has a feminine form also has a masculine form
            return True
    if phonet.hasSimil(sFlex, ":m"):
        return True
    return False


def switchGender (sFlex, bPlur=None):
    # we don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    aSugg = set()
    if bPlur == None:
        for sMorph in _dAnalyses.get(sFlex, []):
            if ":f" in sMorph:
                if ":s" in sMorph:
                    aSugg.add(suggMasSing(sFlex))
                elif ":p" in sMorph:
                    aSugg.add(suggMasPlur(sFlex))
            elif ":m" in sMorph:
                if ":s" in sMorph:
................................................................................
                    aSugg.add(suggFemSing(sFlex))
                elif ":p" in sMorph:
                    aSugg.add(suggFemPlur(sFlex))
                else:
                    aSugg.add(suggFemSing(sFlex))
                    aSugg.add(suggFemPlur(sFlex))
    elif bPlur:
        for sMorph in _dAnalyses.get(sFlex, []):
            if ":f" in sMorph:
                aSugg.add(suggMasPlur(sFlex))
            elif ":m" in sMorph:
                aSugg.add(suggFemPlur(sFlex))
    else:
        for sMorph in _dAnalyses.get(sFlex, []):
            if ":f" in sMorph:
                aSugg.add(suggMasSing(sFlex))
            elif ":m" in sMorph:
                aSugg.add(suggFemSing(sFlex))
    if aSugg:
        return "|".join(aSugg)
    return ""


def switchPlural (sFlex):
    # we don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    aSugg = set()
    for sMorph in _dAnalyses.get(sFlex, []):
        if ":s" in sMorph:
            aSugg.add(suggPlur(sFlex))
        elif ":p" in sMorph:
            aSugg.add(suggSing(sFlex))
    if aSugg:
        return "|".join(aSugg)
    return ""


def hasSimil (sWord, sPattern=None):

    return phonet.hasSimil(sWord, sPattern)


def suggSimil (sWord, sPattern=None, bSubst=False):
    "return list of words phonetically similar to sWord and whom POS is matching sPattern"
    # we don’t check if word exists in _dAnalyses, for it is assumed it has been done before

    aSugg = phonet.selectSimil(sWord, sPattern)
    for sMorph in _dAnalyses.get(sWord, []):

        aSugg.update(conj.getSimil(sWord, sMorph, bSubst))
        break
    if aSugg:


        return "|".join(aSugg)
    return ""


def suggCeOrCet (sWord):

    if re.match("(?i)[aeéèêiouyâîï]", sWord):
        return "cet"
    if sWord[0:1] == "h" or sWord[0:1] == "H":
        return "ce|cet"
    return "ce"


def suggLesLa (sWord):
    # we don’t check if word exists in _dAnalyses, for it is assumed it has been done before
    if any( ":p" in sMorph  for sMorph in _dAnalyses.get(sWord, []) ):
        return "les|la"
    return "la"


_zBinary = re.compile("^[01]+$")

def formatNumber (s):

    nLen = len(s)
    if nLen < 4:
        return s
    sRes = ""
    # nombre ordinaire
    nEnd = nLen
    while nEnd > 0:
................................................................................
    elif nLen == 9 and s.startswith("0"):
        sRes += "|" + s[0:3] + " " + s[3:5] + " " + s[5:7] + " " + s[7:9]                   # fixe belge 1
        sRes += "|" + s[0:2] + " " + s[2:5] + " " + s[5:7] + " " + s[7:9]                   # fixe belge 2
    return sRes


def formatNF (s):

    try:
        m = re.match("NF[  -]?(C|E|P|Q|S|X|Z|EN(?:[  -]ISO|))[  -]?([0-9]+(?:[/‑-][0-9]+|))", s)
        if not m:
            return ""
        return "NF " + m.group(1).upper().replace(" ", " ").replace("-", " ") + " " + m.group(2).replace("/", "‑").replace("-", "‑")
    except:
        traceback.print_exc()
        return "# erreur #"


def undoLigature (c):

    if c == "fi":
        return "fi"
    elif c == "fl":
        return "fl"
    elif c == "ff":
        return "ff"
    elif c == "ffi":
................................................................................


_xNormalizedCharsForInclusiveWriting = str.maketrans({
    '(': '_',  ')': '_',
    '.': '_',  '·': '_',
    '–': '_',  '—': '_',
    '/': '_'
 })


def normalizeInclusiveWriting (sToken):

    return sToken.translate(_xNormalizedCharsForInclusiveWriting)







>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>

|




|
|







 







>
>




|
>

|


|





|

|




|




|




|



|











>

|







|
>
>
>

|









>
>





>
|








>







 







|







 







|
>

|







 







<

<
>







 







<

<
>







 







<

<
>







 







<

<
>







 







>
|








>
|









|


|







 







|





|










|

|










>



|

|
>

<
>



>
>





>








|
|







>







 







>











>







 







|



>

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
..
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
...
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
...
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
...
216
217
218
219
220
221
222

223

224
225
226
227
228
229
230
231
...
243
244
245
246
247
248
249

250

251
252
253
254
255
256
257
258
...
273
274
275
276
277
278
279

280

281
282
283
284
285
286
287
288
...
298
299
300
301
302
303
304

305

306
307
308
309
310
311
312
313
...
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406

407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
...
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
...
501
502
503
504
505
506
507
508
509
510
511
512
513
from . import conj
from . import mfsp
from . import phonet


## Verbs

def splitVerb (sVerb):
    "renvoie le verbe et les pronoms séparément"
    iRight = sVerb.rfind("-")
    sSuffix = sVerb[iRight:]
    sVerb = sVerb[:iRight]
    if sVerb.endswith(("-t", "-le", "-la", "-les")):
        iRight = sVerb.rfind("-")
        sSuffix = sVerb[iRight:] + sSuffix
        sVerb = sVerb[:iRight]
    return sVerb, sSuffix


def suggVerb (sFlex, sWho, funcSugg2=None, bVC=False):
    "change <sFlex> conjugation according to <sWho>"
    if bVC:
        sFlex, sSfx = splitVerb(sFlex)
    aSugg = set()
    for sStem in _oSpellChecker.getLemma(sFlex):
        tTags = conj._getTags(sStem)
        if tTags:
            # we get the tense
            aTense = set()
            for sMorph in _oSpellChecker.getMorph(sFlex):
                for m in re.finditer(">"+sStem+"/.*?(:(?:Y|I[pqsf]|S[pq]|K|P))", sMorph):
                    # stem must be used in regex to prevent confusion between different verbs (e.g. sauras has 2 stems: savoir and saurer)
                    if m:
                        if m.group(1) == ":Y":
                            aTense.add(":Ip")
                            aTense.add(":Iq")
                            aTense.add(":Is")
                        elif m.group(1) == ":P":
................................................................................
                if conj._hasConjWithTags(tTags, sTense, sWho):
                    aSugg.add(conj._getConjWithTags(sStem, tTags, sTense, sWho))
    if funcSugg2:
        aSugg2 = funcSugg2(sFlex)
        if aSugg2:
            aSugg.add(aSugg2)
    if aSugg:
        if bVC:
            aSugg = list(map(lambda sSug: sSug + sSfx, aSugg))
        return "|".join(aSugg)
    return ""


def suggVerbPpas (sFlex, sPattern=None):
    "suggest past participles for <sFlex>"
    aSugg = set()
    for sStem in _oSpellChecker.getLemma(sFlex):
        tTags = conj._getTags(sStem)
        if tTags:
            if not sPattern:
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"))
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q2"))
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q3"))
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q4"))
                aSugg.discard("")
            elif sPattern == ":m:s":
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"))
            elif sPattern == ":m:p":
                if conj._hasConjWithTags(tTags, ":PQ", ":Q2"):
                    aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q2"))
                else:
                    aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"))
            elif sPattern == ":f:s":
                if conj._hasConjWithTags(tTags, ":PQ", ":Q3"):
                    aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q3"))
                else:
                    aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"))
            elif sPattern == ":f:p":
                if conj._hasConjWithTags(tTags, ":PQ", ":Q4"):
                    aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q4"))
                else:
                    aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"))
            elif sPattern == ":s":
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"))
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q3"))
                aSugg.discard("")
            elif sPattern == ":p":
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q2"))
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q4"))
                aSugg.discard("")
            else:
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":PQ", ":Q1"))
    if aSugg:
        return "|".join(aSugg)
    return ""


def suggVerbTense (sFlex, sTense, sWho):
    "change <sFlex> to a verb according to <sTense> and <sWho>"
    aSugg = set()
    for sStem in _oSpellChecker.getLemma(sFlex):
        if conj.hasConj(sStem, sTense, sWho):
            aSugg.add(conj.getConj(sStem, sTense, sWho))
    if aSugg:
        return "|".join(aSugg)
    return ""


def suggVerbImpe (sFlex, bVC=False):
    "change <sFlex> to a verb at imperative form"
    if bVC:
        sFlex, sSfx = splitVerb(sFlex)
    aSugg = set()
    for sStem in _oSpellChecker.getLemma(sFlex):
        tTags = conj._getTags(sStem)
        if tTags:
            if conj._hasConjWithTags(tTags, ":E", ":2s"):
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":E", ":2s"))
            if conj._hasConjWithTags(tTags, ":E", ":1p"):
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":E", ":1p"))
            if conj._hasConjWithTags(tTags, ":E", ":2p"):
                aSugg.add(conj._getConjWithTags(sStem, tTags, ":E", ":2p"))
    if aSugg:
        if bVC:
            aSugg = list(map(lambda sSug: sSug + sSfx, aSugg))
        return "|".join(aSugg)
    return ""


def suggVerbInfi (sFlex):
    "returns infinitive forms of <sFlex>"
    return "|".join([ sStem  for sStem in _oSpellChecker.getLemma(sFlex)  if conj.isVerb(sStem) ])


_dQuiEst = { "je": ":1s", "j’": ":1s", "j’en": ":1s", "j’y": ":1s", \
             "tu": ":2s", "il": ":3s", "on": ":3s", "elle": ":3s", "nous": ":1p", "vous": ":2p", "ils": ":3p", "elles": ":3p" }
_lIndicatif = [":Ip", ":Iq", ":Is", ":If"]
_lSubjonctif = [":Sp", ":Sq"]

def suggVerbMode (sFlex, cMode, sSuj):
    "returns other conjugations of <sFlex> acconding to <cMode> and <sSuj>"
    if cMode == ":I":
        lMode = _lIndicatif
    elif cMode == ":S":
        lMode = _lSubjonctif
    elif cMode.startswith((":I", ":S")):
        lMode = [cMode]
    else:
................................................................................
        return ""
    sWho = _dQuiEst.get(sSuj.lower(), None)
    if not sWho:
        if sSuj[0:1].islower(): # pas un pronom, ni un nom propre
            return ""
        sWho = ":3s"
    aSugg = set()
    for sStem in _oSpellChecker.getLemma(sFlex):
        tTags = conj._getTags(sStem)
        if tTags:
            for sTense in lMode:
                if conj._hasConjWithTags(tTags, sTense, sWho):
                    aSugg.add(conj._getConjWithTags(sStem, tTags, sTense, sWho))
    if aSugg:
        return "|".join(aSugg)
................................................................................


## Nouns and adjectives

def suggPlur (sFlex, sWordToAgree=None):
    "returns plural forms assuming sFlex is singular"
    if sWordToAgree:
        lMorph = _oSpellChecker.getMorph(sFlex)
        if not lMorph:
            return ""
        sGender = cr.getGender(lMorph)
        if sGender == ":m":
            return suggMasPlur(sFlex)
        elif sGender == ":f":
            return suggFemPlur(sFlex)
    aSugg = set()
    if "-" not in sFlex:
        if sFlex.endswith("l"):
................................................................................
    if aSugg:
        return "|".join(aSugg)
    return ""


def suggMasSing (sFlex, bSuggSimil=False):
    "returns masculine singular forms"

    aSugg = set()

    for sMorph in _oSpellChecker.getMorph(sFlex):
        if not ":V" in sMorph:
            # not a verb
            if ":m" in sMorph or ":e" in sMorph:
                aSugg.add(suggSing(sFlex))
            else:
                sStem = cr.getLemmaOfMorph(sMorph)
                if mfsp.isFemForm(sStem):
................................................................................
    if aSugg:
        return "|".join(aSugg)
    return ""


def suggMasPlur (sFlex, bSuggSimil=False):
    "returns masculine plural forms"

    aSugg = set()

    for sMorph in _oSpellChecker.getMorph(sFlex):
        if not ":V" in sMorph:
            # not a verb
            if ":m" in sMorph or ":e" in sMorph:
                aSugg.add(suggPlur(sFlex))
            else:
                sStem = cr.getLemmaOfMorph(sMorph)
                if mfsp.isFemForm(sStem):
................................................................................
    if aSugg:
        return "|".join(aSugg)
    return ""


def suggFemSing (sFlex, bSuggSimil=False):
    "returns feminine singular forms"

    aSugg = set()

    for sMorph in _oSpellChecker.getMorph(sFlex):
        if not ":V" in sMorph:
            # not a verb
            if ":f" in sMorph or ":e" in sMorph:
                aSugg.add(suggSing(sFlex))
            else:
                sStem = cr.getLemmaOfMorph(sMorph)
                if mfsp.isFemForm(sStem):
................................................................................
    if aSugg:
        return "|".join(aSugg)
    return ""


def suggFemPlur (sFlex, bSuggSimil=False):
    "returns feminine plural forms"

    aSugg = set()

    for sMorph in _oSpellChecker.getMorph(sFlex):
        if not ":V" in sMorph:
            # not a verb
            if ":f" in sMorph or ":e" in sMorph:
                aSugg.add(suggPlur(sFlex))
            else:
                sStem = cr.getLemmaOfMorph(sMorph)
                if mfsp.isFemForm(sStem):
................................................................................
            aSugg.add(e)
    if aSugg:
        return "|".join(aSugg)
    return ""


def hasFemForm (sFlex):
    "return True if there is a feminine form of <sFlex>"
    for sStem in _oSpellChecker.getLemma(sFlex):
        if mfsp.isFemForm(sStem) or conj.hasConj(sStem, ":PQ", ":Q3"):
            return True
    if phonet.hasSimil(sFlex, ":f"):
        return True
    return False


def hasMasForm (sFlex):
    "return True if there is a masculine form of <sFlex>"
    for sStem in _oSpellChecker.getLemma(sFlex):
        if mfsp.isFemForm(sStem) or conj.hasConj(sStem, ":PQ", ":Q1"):
            # what has a feminine form also has a masculine form
            return True
    if phonet.hasSimil(sFlex, ":m"):
        return True
    return False


def switchGender (sFlex, bPlur=None):
    "return feminine or masculine form(s) of <sFlex>"
    aSugg = set()
    if bPlur == None:
        for sMorph in _oSpellChecker.getMorph(sFlex):
            if ":f" in sMorph:
                if ":s" in sMorph:
                    aSugg.add(suggMasSing(sFlex))
                elif ":p" in sMorph:
                    aSugg.add(suggMasPlur(sFlex))
            elif ":m" in sMorph:
                if ":s" in sMorph:
................................................................................
                    aSugg.add(suggFemSing(sFlex))
                elif ":p" in sMorph:
                    aSugg.add(suggFemPlur(sFlex))
                else:
                    aSugg.add(suggFemSing(sFlex))
                    aSugg.add(suggFemPlur(sFlex))
    elif bPlur:
        for sMorph in _oSpellChecker.getMorph(sFlex):
            if ":f" in sMorph:
                aSugg.add(suggMasPlur(sFlex))
            elif ":m" in sMorph:
                aSugg.add(suggFemPlur(sFlex))
    else:
        for sMorph in _oSpellChecker.getMorph(sFlex):
            if ":f" in sMorph:
                aSugg.add(suggMasSing(sFlex))
            elif ":m" in sMorph:
                aSugg.add(suggFemSing(sFlex))
    if aSugg:
        return "|".join(aSugg)
    return ""


def switchPlural (sFlex):
    "return plural or singular form(s) of <sFlex>"
    aSugg = set()
    for sMorph in _oSpellChecker.getMorph(sFlex):
        if ":s" in sMorph:
            aSugg.add(suggPlur(sFlex))
        elif ":p" in sMorph:
            aSugg.add(suggSing(sFlex))
    if aSugg:
        return "|".join(aSugg)
    return ""


def hasSimil (sWord, sPattern=None):
    "return True if there is words phonetically similar to <sWord> (according to <sPattern> if required)"
    return phonet.hasSimil(sWord, sPattern)


def suggSimil (sWord, sPattern=None, bSubst=False, bVC=False):
    "return list of words phonetically similar to sWord and whom POS is matching sPattern"
    if bVC:
        sWord, sSfx = splitVerb(sWord)
    aSugg = phonet.selectSimil(sWord, sPattern)

    for sMorph in _oSpellChecker.getMorph(sWord):
        aSugg.update(conj.getSimil(sWord, sMorph, bSubst))
        break
    if aSugg:
        if bVC:
            aSugg = list(map(lambda sSug: sSug + sSfx, aSugg))
        return "|".join(aSugg)
    return ""


def suggCeOrCet (sWord):
    "suggest “ce” or “cet” or both according to the first letter of <sWord>"
    if re.match("(?i)[aeéèêiouyâîï]", sWord):
        return "cet"
    if sWord[0:1] == "h" or sWord[0:1] == "H":
        return "ce|cet"
    return "ce"


def suggLesLa (sWord):
    "suggest “les” or “la” according to <sWord>"
    if any( ":p" in sMorph  for sMorph in _oSpellChecker.getMorph(sWord) ):
        return "les|la"
    return "la"


_zBinary = re.compile("^[01]+$")

def formatNumber (s):
    "add spaces or hyphens to big numbers"
    nLen = len(s)
    if nLen < 4:
        return s
    sRes = ""
    # nombre ordinaire
    nEnd = nLen
    while nEnd > 0:
................................................................................
    elif nLen == 9 and s.startswith("0"):
        sRes += "|" + s[0:3] + " " + s[3:5] + " " + s[5:7] + " " + s[7:9]                   # fixe belge 1
        sRes += "|" + s[0:2] + " " + s[2:5] + " " + s[5:7] + " " + s[7:9]                   # fixe belge 2
    return sRes


def formatNF (s):
    "typography: format NF reference (norme française)"
    try:
        m = re.match("NF[  -]?(C|E|P|Q|S|X|Z|EN(?:[  -]ISO|))[  -]?([0-9]+(?:[/‑-][0-9]+|))", s)
        if not m:
            return ""
        return "NF " + m.group(1).upper().replace(" ", " ").replace("-", " ") + " " + m.group(2).replace("/", "‑").replace("-", "‑")
    except:
        traceback.print_exc()
        return "# erreur #"


def undoLigature (c):
    "typography: split ligature character <c> in several chars"
    if c == "fi":
        return "fi"
    elif c == "fl":
        return "fl"
    elif c == "ff":
        return "ff"
    elif c == "ffi":
................................................................................


_xNormalizedCharsForInclusiveWriting = str.maketrans({
    '(': '_',  ')': '_',
    '.': '_',  '·': '_',
    '–': '_',  '—': '_',
    '/': '_'
})


def normalizeInclusiveWriting (sToken):
    "typography: replace word separators used in inclusive writing by underscore (_)"
    return sToken.translate(_xNormalizedCharsForInclusiveWriting)

Modified gc_lang/fr/modules/lexicographe.py from [5e53113f51] to [175c38852d].


1


2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
...
151
152
153
154
155
156
157

158
159
160
161
162
163
164
165

166
167
168
169
170
171
172
...
190
191
192
193
194
195
196
197
198
199
200
201
202
203

204
205
206
207
208
209
210

# Grammalecte - Lexicographe


# License: MPL 2


import re
import traceback


_dTAGS = {  
    ':N': (" nom,", "Nom"),
    ':A': (" adjectif,", "Adjectif"),
    ':M1': (" prénom,", "Prénom"),
    ':M2': (" patronyme,", "Patronyme, matronyme, nom de famille…"),
    ':MP': (" nom propre,", "Nom propre"),
    ':W': (" adverbe,", "Adverbe"),
    ':J': (" interjection,", "Interjection"),
................................................................................
    ':O2': (" 2ᵉ pers.,", "Pronom : 2ᵉ personne"),
    ':O3': (" 3ᵉ pers.,", "Pronom : 3ᵉ personne"),
    ':C': (" conjonction,", "Conjonction"),
    ':Ĉ': (" conjonction (él.),", "Conjonction (élément)"),
    ':Cc': (" conjonction de coordination,", "Conjonction de coordination"),
    ':Cs': (" conjonction de subordination,", "Conjonction de subordination"),
    ':Ĉs': (" conjonction de subordination (él.),", "Conjonction de subordination (élément)"),
    
    ':Ñ': (" locution nominale (él.),", "Locution nominale (élément)"),
    ':Â': (" locution adjectivale (él.),", "Locution adjectivale (élément)"),
    ':Ṽ': (" locution verbale (él.),", "Locution verbale (élément)"),
    ':Ŵ': (" locution adverbiale (él.),", "Locution adverbiale (élément)"),
    ':Ŕ': (" locution prépositive (él.),", "Locution prépositive (élément)"),
    ':Ĵ': (" locution interjective (él.),", "Locution interjective (élément)"),

................................................................................
    'il': " pronom personnel sujet, 3ᵉ pers. masc. sing.",
    'on': " pronom personnel sujet, 3ᵉ pers. sing. ou plur.",
    'elle': " pronom personnel sujet, 3ᵉ pers. fém. sing.",
    'nous': " pronom personnel sujet/objet, 1ʳᵉ pers. plur.",
    'vous': " pronom personnel sujet/objet, 2ᵉ pers. plur.",
    'ils': " pronom personnel sujet, 3ᵉ pers. masc. plur.",
    'elles': " pronom personnel sujet, 3ᵉ pers. masc. plur.",
    
    "là": " particule démonstrative",
    "ci": " particule démonstrative",
    
    'le': " COD, masc. sing.",
    'la': " COD, fém. sing.",
    'les': " COD, plur.",
        
    'moi': " COI (à moi), sing.",
    'toi': " COI (à toi), sing.",
    'lui': " COI (à lui ou à elle), sing.",
    'nous2': " COI (à nous), plur.",
    'vous2': " COI (à vous), plur.",
    'leur': " COI (à eux ou à elles), plur.",

................................................................................
    "m'en": " (me) pronom personnel objet + (en) pronom adverbial",
    "t'en": " (te) pronom personnel objet + (en) pronom adverbial",
    "s'en": " (se) pronom personnel objet + (en) pronom adverbial",
}


class Lexicographe:


    def __init__ (self, oSpellChecker):
        self.oSpellChecker = oSpellChecker
        self._zElidedPrefix = re.compile("(?i)^([dljmtsncç]|quoiqu|lorsqu|jusqu|puisqu|qu)['’](.+)")
        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)$")
        self._zTag = re.compile("[:;/][\\w*][^:;/]*")

    def analyzeWord (self, sWord):

        try:
            if not sWord:
                return (None, None)
            if sWord.count("-") > 4:
                return (["élément complexe indéterminé"], None)
            if sWord.isdigit():
                return (["nombre"], None)
................................................................................
                aMorph.append( "{} : {}".format(sWord, self.formatTags(lMorph[0])) )
            else:
                aMorph.append( "{} :  inconnu du dictionnaire".format(sWord) )
            # suffixe d’un mot composé
            if m2:
                aMorph.append( "-{} : {}".format(m2.group(2), self._formatSuffix(m2.group(2).lower())) )
            # Verbes
            aVerb = set([ s[1:s.find(" ")]  for s in lMorph  if ":V" in s ])
            return (aMorph, aVerb)
        except:
            traceback.print_exc()
            return (["#erreur"], None)

    def formatTags (self, sTags):

        sRes = ""
        sTags = re.sub("(?<=V[1-3])[itpqnmr_eaxz]+", "", sTags)
        sTags = re.sub("(?<=V0[ea])[itpqnmr_eaxz]+", "", sTags)
        for m in self._zTag.finditer(sTags):
            sRes += _dTAGS.get(m.group(0), " [{}]".format(m.group(0)))[0]
        if sRes.startswith(" verbe") and not sRes.endswith("infinitif"):
            sRes += " [{}]".format(sTags[1:sTags.find(" ")])
>
|
>
>







|







 







|







 







|


|



|







 







>








>







 







|






>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
...
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
"""
Grammalecte - Lexicographe
"""

# License: MPL 2


import re
import traceback


_dTAGS = {
    ':N': (" nom,", "Nom"),
    ':A': (" adjectif,", "Adjectif"),
    ':M1': (" prénom,", "Prénom"),
    ':M2': (" patronyme,", "Patronyme, matronyme, nom de famille…"),
    ':MP': (" nom propre,", "Nom propre"),
    ':W': (" adverbe,", "Adverbe"),
    ':J': (" interjection,", "Interjection"),
................................................................................
    ':O2': (" 2ᵉ pers.,", "Pronom : 2ᵉ personne"),
    ':O3': (" 3ᵉ pers.,", "Pronom : 3ᵉ personne"),
    ':C': (" conjonction,", "Conjonction"),
    ':Ĉ': (" conjonction (él.),", "Conjonction (élément)"),
    ':Cc': (" conjonction de coordination,", "Conjonction de coordination"),
    ':Cs': (" conjonction de subordination,", "Conjonction de subordination"),
    ':Ĉs': (" conjonction de subordination (él.),", "Conjonction de subordination (élément)"),

    ':Ñ': (" locution nominale (él.),", "Locution nominale (élément)"),
    ':Â': (" locution adjectivale (él.),", "Locution adjectivale (élément)"),
    ':Ṽ': (" locution verbale (él.),", "Locution verbale (élément)"),
    ':Ŵ': (" locution adverbiale (él.),", "Locution adverbiale (élément)"),
    ':Ŕ': (" locution prépositive (él.),", "Locution prépositive (élément)"),
    ':Ĵ': (" locution interjective (él.),", "Locution interjective (élément)"),

................................................................................
    'il': " pronom personnel sujet, 3ᵉ pers. masc. sing.",
    'on': " pronom personnel sujet, 3ᵉ pers. sing. ou plur.",
    'elle': " pronom personnel sujet, 3ᵉ pers. fém. sing.",
    'nous': " pronom personnel sujet/objet, 1ʳᵉ pers. plur.",
    'vous': " pronom personnel sujet/objet, 2ᵉ pers. plur.",
    'ils': " pronom personnel sujet, 3ᵉ pers. masc. plur.",
    'elles': " pronom personnel sujet, 3ᵉ pers. masc. plur.",

    "là": " particule démonstrative",
    "ci": " particule démonstrative",

    'le': " COD, masc. sing.",
    'la': " COD, fém. sing.",
    'les': " COD, plur.",

    'moi': " COI (à moi), sing.",
    'toi': " COI (à toi), sing.",
    'lui': " COI (à lui ou à elle), sing.",
    'nous2': " COI (à nous), plur.",
    'vous2': " COI (à vous), plur.",
    'leur': " COI (à eux ou à elles), plur.",

................................................................................
    "m'en": " (me) pronom personnel objet + (en) pronom adverbial",
    "t'en": " (te) pronom personnel objet + (en) pronom adverbial",
    "s'en": " (se) pronom personnel objet + (en) pronom adverbial",
}


class Lexicographe:
    "Lexicographer - word analyzer"

    def __init__ (self, oSpellChecker):
        self.oSpellChecker = oSpellChecker
        self._zElidedPrefix = re.compile("(?i)^([dljmtsncç]|quoiqu|lorsqu|jusqu|puisqu|qu)['’](.+)")
        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)$")
        self._zTag = re.compile("[:;/][\\w*][^:;/]*")

    def analyzeWord (self, sWord):
        "returns a tuple (a list of morphologies, a set of verb at infinitive form)"
        try:
            if not sWord:
                return (None, None)
            if sWord.count("-") > 4:
                return (["élément complexe indéterminé"], None)
            if sWord.isdigit():
                return (["nombre"], None)
................................................................................
                aMorph.append( "{} : {}".format(sWord, self.formatTags(lMorph[0])) )
            else:
                aMorph.append( "{} :  inconnu du dictionnaire".format(sWord) )
            # suffixe d’un mot composé
            if m2:
                aMorph.append( "-{} : {}".format(m2.group(2), self._formatSuffix(m2.group(2).lower())) )
            # Verbes
            aVerb = set([ s[1:s.find("/")]  for s in lMorph  if ":V" in s ])
            return (aMorph, aVerb)
        except:
            traceback.print_exc()
            return (["#erreur"], None)

    def formatTags (self, sTags):
        "returns string: readable tags"
        sRes = ""
        sTags = re.sub("(?<=V[1-3])[itpqnmr_eaxz]+", "", sTags)
        sTags = re.sub("(?<=V0[ea])[itpqnmr_eaxz]+", "", sTags)
        for m in self._zTag.finditer(sTags):
            sRes += _dTAGS.get(m.group(0), " [{}]".format(m.group(0)))[0]
        if sRes.startswith(" verbe") and not sRes.endswith("infinitif"):
            sRes += " [{}]".format(sTags[1:sTags.find(" ")])

Modified gc_lang/fr/modules/mfsp.py from [3f4814b5d6] to [8b7759e076].


1

2
3
4
5
6
7
8

# Masculins, féminins, singuliers et pluriels


from .mfsp_data import lTagMiscPlur as _lTagMiscPlur
from .mfsp_data import lTagMasForm as _lTagMasForm
from .mfsp_data import dMiscPlur as _dMiscPlur
from .mfsp_data import dMasForm as _dMasForm


>
|
>







1
2
3
4
5
6
7
8
9
10
"""
Masculins, féminins, singuliers et pluriels
"""

from .mfsp_data import lTagMiscPlur as _lTagMiscPlur
from .mfsp_data import lTagMasForm as _lTagMasForm
from .mfsp_data import dMiscPlur as _dMiscPlur
from .mfsp_data import dMasForm as _dMasForm


Modified gc_lang/fr/modules/mfsp_data.py from [7dfa66bd8d] to [06d2bb2ead].

cannot compute difference between binary files

Modified gc_lang/fr/modules/phonet.py from [cc107e0763] to [df9f884192].


1


2
3
4
5
6
7
8

# Grammalecte - Suggestion phonétique


# License: GPL 3

import re

from .phonet_data import dWord as _dWord
from .phonet_data import lSet as _lSet
from .phonet_data import dMorph as _dMorph
>
|
>
>







1
2
3
4
5
6
7
8
9
10
11
"""
Grammalecte - Suggestion phonétique
"""

# License: GPL 3

import re

from .phonet_data import dWord as _dWord
from .phonet_data import lSet as _lSet
from .phonet_data import dMorph as _dMorph

Modified gc_lang/fr/modules/phonet_data.py from [9980015f68] to [e596111a28].

cannot compute difference between binary files

Modified gc_lang/fr/modules/tests.py from [2e6f413e05] to [83f9fd0bb6].

1
2




3
4
5
6
7
8
9
...
125
126
127
128
129
130
131

132
133
134
135
136
137
138
...
143
144
145
146
147
148
149
150

151
152
153
154
155

156


157






158
159
160
161
162
163
164
#! python3
# coding: UTF-8





import unittest
import os
import re
import time


................................................................................
        cls._zError = re.compile(r"\{\{.*?\}\}")
        cls._aRuleTested = set()

    def test_parse (self):
        zOption = re.compile("^__([a-zA-Z0-9]+)__ ")
        spHere, spfThisFile = os.path.split(__file__)
        with open(os.path.join(spHere, "gc_test.txt"), "r", encoding="utf-8") as hSrc:

            for sLine in ( s for s in hSrc if not s.startswith("#") and s.strip() ):
                sLineNum = sLine[:10].strip()
                sLine = sLine[10:].strip()
                sOption = None
                m = zOption.search(sLine)
                if m:
                    sLine = sLine[m.end():]
................................................................................
                        sExceptedSuggs = sExceptedSuggs[1:-1]
                else:
                    sErrorText = sLine.strip()
                    sExceptedSuggs = ""
                sExpectedErrors = self._getExpectedErrors(sErrorText)
                sTextToCheck = sErrorText.replace("}}", "").replace("{{", "")
                sFoundErrors, sListErr, sFoundSuggs = self._getFoundErrors(sTextToCheck, sOption)
                self.assertEqual(sExpectedErrors, sFoundErrors, \

                                 "\n# Line num: " + sLineNum + \
                                 "\n> to check: " + _fuckBackslashUTF8(sTextToCheck) + \
                                 "\n  expected: " + sExpectedErrors + \
                                 "\n  found:    " + sFoundErrors + \
                                 "\n  errors:   \n" + sListErr)

                if sExceptedSuggs:


                    self.assertEqual(sExceptedSuggs, sFoundSuggs, "\n# Line num: " + sLineNum + "\n> to check: " + _fuckBackslashUTF8(sTextToCheck) + "\n  errors:   \n" + sListErr)






        # untested rules
        i = 0
        for sOpt, sLineId, sRuleId in gce.listRules():
            if sLineId not in self._aRuleTested and not re.search("^[0-9]+[sp]$|^[pd]_", sRuleId):
                echo(sRuleId, end= ", ")
                i += 1
        if i:

<
>
>
>
>







 







>







 







|
>
|
|
|
|
|
>
|
>
>
|
>
>
>
>
>
>







1

2
3
4
5
6
7
8
9
10
11
12
...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#! python3


"""
Grammar checker tests for French language
"""

import unittest
import os
import re
import time


................................................................................
        cls._zError = re.compile(r"\{\{.*?\}\}")
        cls._aRuleTested = set()

    def test_parse (self):
        zOption = re.compile("^__([a-zA-Z0-9]+)__ ")
        spHere, spfThisFile = os.path.split(__file__)
        with open(os.path.join(spHere, "gc_test.txt"), "r", encoding="utf-8") as hSrc:
            nError = 0
            for sLine in ( s for s in hSrc if not s.startswith("#") and s.strip() ):
                sLineNum = sLine[:10].strip()
                sLine = sLine[10:].strip()
                sOption = None
                m = zOption.search(sLine)
                if m:
                    sLine = sLine[m.end():]
................................................................................
                        sExceptedSuggs = sExceptedSuggs[1:-1]
                else:
                    sErrorText = sLine.strip()
                    sExceptedSuggs = ""
                sExpectedErrors = self._getExpectedErrors(sErrorText)
                sTextToCheck = sErrorText.replace("}}", "").replace("{{", "")
                sFoundErrors, sListErr, sFoundSuggs = self._getFoundErrors(sTextToCheck, sOption)
                # tests
                if sExpectedErrors != sFoundErrors:
                    print("\n# Line num: " + sLineNum + \
                          "\n> to check: " + _fuckBackslashUTF8(sTextToCheck) + \
                          "\n  expected: " + sExpectedErrors + \
                          "\n  found:    " + sFoundErrors + \
                          "\n  errors:   \n" + sListErr)
                    nError += 1
                elif sExceptedSuggs:
                    if sExceptedSuggs != sFoundSuggs:
                        print("\n# Line num: " + sLineNum + \
                              "\n> to check: " + _fuckBackslashUTF8(sTextToCheck) + \
                              "\n  expected: " + sExceptedSuggs + \
                              "\n  found:    " + sFoundSuggs + \
                              "\n  errors:   \n" + sListErr)
                        nError += 1
            if nError:
                print("Unexpected errors:", nError)
        # untested rules
        i = 0
        for sOpt, sLineId, sRuleId in gce.listRules():
            if sLineId not in self._aRuleTested and not re.search("^[0-9]+[sp]$|^[pd]_", sRuleId):
                echo(sRuleId, end= ", ")
                i += 1
        if i:

Modified gc_lang/fr/modules/textformatter.py from [8fb9ec33bf] to [219d3111da].

1




2
3
4
5
6
7
8
..
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
..
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#!python3





import re


dReplTable = {
    # surnumerary_spaces
    "start_of_paragraph":          [("^[  ]+", "")],
................................................................................
    # common
    "nbsp_titles":                 [("\\bM(mes?|ᵐᵉˢ?|grs?|ᵍʳˢ?|lles?|ˡˡᵉˢ?|rs?|ʳˢ?|M\\.) ", "M\\1 "),
                                    ("\\bP(re?s?|ʳᵉ?ˢ?) ", "P\\1 "),
                                    ("\\bD(re?s?|ʳᵉ?ˢ?) ", "D\\1 "),
                                    ("\\bV(ves?|ᵛᵉˢ?) ", "V\\1 ")],
    "nbsp_before_symbol":          [("(\\d) ?([%‰€$£¥˚Ω℃])", "\\1 \\2")],
    "nbsp_before_units":           [("(?<=[0-9⁰¹²³⁴⁵⁶⁷⁸⁹]) ?([kcmµn]?(?:[slgJKΩ]|m[²³]?|Wh?|Hz|dB)|[%‰]|°C)\\b", " \\1")],
    "nbsp_repair":                 [("(?<=[[(])[   ]([!?:;])", "\\1"),
                                    ("(https?|ftp)[   ]:(?=//)", "\\1:"),
                                    ("&([a-z]+)[   ];", "&\\1;"),
                                    ("&#([0-9]+|x[0-9a-fA-F]+)[   ];", "&#\\1;")],
    ## missing spaces
    "add_space_after_punctuation": [("([;!…])(?=\\w)", "\\1 "),
                                    ("[?](?=[A-ZÉÈÊÂÀÎ])", "? "),
                                    ("\\.(?=[A-ZÉÈÎ][a-zA-ZàâÂéÉèÈêÊîÎïÏôÔöÖûÛüÜùÙ])", ". "),
................................................................................
    "erase_non_breaking_hyphens":  [("­", "")],
    ## typographic signs
    "ts_apostrophe":          [ ("(?i)\\b([ldnjmtscç])['´‘′`](?=\\w)", "\\1’"),
                                ("(?i)(qu|jusqu|lorsqu|puisqu|quoiqu|quelqu|presqu|entr|aujourd|prud)['´‘′`]", "\\1’") ],
    "ts_ellipsis":            [ ("\\.\\.\\.", "…"),
                                ("(?<=…)[.][.]", "…"),
                                ("…[.](?![.])", "…") ],
    "ts_n_dash_middle":       [ (" [-—] ", " – "), 
                                (" [-—],", " –,") ],
    "ts_m_dash_middle":       [ (" [-–] ", " — "),
                                (" [-–],", " —,") ],
    "ts_n_dash_start":        [ ("^[-—][  ]", "– "),
                                ("^– ", "– "),
                                ("^[-–—](?=[\\w.…])", "– ") ],
    "ts_m_dash_start":        [ ("^[-–][  ]", "— "),
                                ("^— ", "— "),
                                ("^«[  ][—–-][  ]", "« — "),
                                ("^[-–—](?=[\\w.…])", "— ") ],
    "ts_quotation_marks":     [ (u'"(\\w+)"', "“$1”"),
                                ("''(\\w+)''", "“$1”"),
                                ("'(\\w+)'", "“$1”"),
                                ("^(?:\"|'')(?=\\w)", "« "),
                                (" (?:\"|'')(?=\\w)", " « "),
                                ("\\((?:\"|'')(?=\\w)", "(« "),
                                ("(?<=\\w)(?:\"|'')$", " »"),
                                ("(?<=\\w)(?:\"|'')(?=[] ,.:;?!…)])", " »"),
                                (u'(?<=[.!?…])" ', " » "),
                                (u'(?<=[.!?…])"$', " »") ],
    "ts_spell":               [ ("coeur", "cœur"), ("Coeur", "Cœur"),
                                ("coel(?=[aeio])", "cœl"), ("Coel(?=[aeio])", "Cœl"),
                                ("choeur", "chœur"), ("Choeur", "Chœur"),
                                ("foet", "fœt"), ("Foet", "Fœt"),
                                ("oeil", "œil"), ("Oeil", "Œil"),
                                ("oeno", "œno"), ("Oeno", "Œno"),
                                ("oesoph", "œsoph"), ("Oesoph", "Œsoph"),

>
>
>
>







 







|







 







|










|







|
|







1
2
3
4
5
6
7
8
9
10
11
12
..
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
..
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#!python3

"""
Text formatter
"""

import re


dReplTable = {
    # surnumerary_spaces
    "start_of_paragraph":          [("^[  ]+", "")],
................................................................................
    # common
    "nbsp_titles":                 [("\\bM(mes?|ᵐᵉˢ?|grs?|ᵍʳˢ?|lles?|ˡˡᵉˢ?|rs?|ʳˢ?|M\\.) ", "M\\1 "),
                                    ("\\bP(re?s?|ʳᵉ?ˢ?) ", "P\\1 "),
                                    ("\\bD(re?s?|ʳᵉ?ˢ?) ", "D\\1 "),
                                    ("\\bV(ves?|ᵛᵉˢ?) ", "V\\1 ")],
    "nbsp_before_symbol":          [("(\\d) ?([%‰€$£¥˚Ω℃])", "\\1 \\2")],
    "nbsp_before_units":           [("(?<=[0-9⁰¹²³⁴⁵⁶⁷⁸⁹]) ?([kcmµn]?(?:[slgJKΩ]|m[²³]?|Wh?|Hz|dB)|[%‰]|°C)\\b", " \\1")],
    "nbsp_repair":                 [("(?<=[\\[(])[   ]([!?:;])", "\\1"),
                                    ("(https?|ftp)[   ]:(?=//)", "\\1:"),
                                    ("&([a-z]+)[   ];", "&\\1;"),
                                    ("&#([0-9]+|x[0-9a-fA-F]+)[   ];", "&#\\1;")],
    ## missing spaces
    "add_space_after_punctuation": [("([;!…])(?=\\w)", "\\1 "),
                                    ("[?](?=[A-ZÉÈÊÂÀÎ])", "? "),
                                    ("\\.(?=[A-ZÉÈÎ][a-zA-ZàâÂéÉèÈêÊîÎïÏôÔöÖûÛüÜùÙ])", ". "),
................................................................................
    "erase_non_breaking_hyphens":  [("­", "")],
    ## typographic signs
    "ts_apostrophe":          [ ("(?i)\\b([ldnjmtscç])['´‘′`](?=\\w)", "\\1’"),
                                ("(?i)(qu|jusqu|lorsqu|puisqu|quoiqu|quelqu|presqu|entr|aujourd|prud)['´‘′`]", "\\1’") ],
    "ts_ellipsis":            [ ("\\.\\.\\.", "…"),
                                ("(?<=…)[.][.]", "…"),
                                ("…[.](?![.])", "…") ],
    "ts_n_dash_middle":       [ (" [-—] ", " – "),
                                (" [-—],", " –,") ],
    "ts_m_dash_middle":       [ (" [-–] ", " — "),
                                (" [-–],", " —,") ],
    "ts_n_dash_start":        [ ("^[-—][  ]", "– "),
                                ("^– ", "– "),
                                ("^[-–—](?=[\\w.…])", "– ") ],
    "ts_m_dash_start":        [ ("^[-–][  ]", "— "),
                                ("^— ", "— "),
                                ("^«[  ][—–-][  ]", "« — "),
                                ("^[-–—](?=[\\w.…])", "— ") ],
    "ts_quotation_marks":     [ ('"(\\w+)"', "“$1”"),
                                ("''(\\w+)''", "“$1”"),
                                ("'(\\w+)'", "“$1”"),
                                ("^(?:\"|'')(?=\\w)", "« "),
                                (" (?:\"|'')(?=\\w)", " « "),
                                ("\\((?:\"|'')(?=\\w)", "(« "),
                                ("(?<=\\w)(?:\"|'')$", " »"),
                                ("(?<=\\w)(?:\"|'')(?=[] ,.:;?!…)])", " »"),
                                ('(?<=[.!?…])" ', " » "),
                                ('(?<=[.!?…])"$', " »") ],
    "ts_spell":               [ ("coeur", "cœur"), ("Coeur", "Cœur"),
                                ("coel(?=[aeio])", "cœl"), ("Coel(?=[aeio])", "Cœl"),
                                ("choeur", "chœur"), ("Choeur", "Chœur"),
                                ("foet", "fœt"), ("Foet", "Fœt"),
                                ("oeil", "œil"), ("Oeil", "Œil"),
                                ("oeno", "œno"), ("Oeno", "Œno"),
                                ("oesoph", "œsoph"), ("Oesoph", "Œsoph"),

Modified gc_lang/fr/oxt/Dictionnaires/dictionaries/README_dict_fr.txt from [3e9744d110] to [dee0f21f2d].

1
2
3
4
5
6
7
8
9
10
11
_______________________________________________________________________________

   DICTIONNAIRES ORTHOGRAPHIQUES FRANÇAIS
   version 6.3

   Olivier R. - dicollecte<at>free<dot>fr
   Dicollecte : http://www.dicollecte.org/

   Licence :
     MPL : Mozilla Public License
     version 2.0  --  http://www.mozilla.org/MPL/2.0/



|







1
2
3
4
5
6
7
8
9
10
11
_______________________________________________________________________________

   DICTIONNAIRES ORTHOGRAPHIQUES FRANÇAIS
   version 7.0

   Olivier R. - dicollecte<at>free<dot>fr
   Dicollecte : http://www.dicollecte.org/

   Licence :
     MPL : Mozilla Public License
     version 2.0  --  http://www.mozilla.org/MPL/2.0/

Modified gc_lang/fr/oxt/Dictionnaires/dictionaries/fr-classique.aff from [7aba573e1d] to [b598faf4d9].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

# AFFIXES DU DICTIONNAIRE ORTHOGRAPHIQUE FRANÇAIS “CLASSIQUE” v6.3
# par Olivier R. -- licence MPL 2.0
# Généré le 05-05-2018 à 15:38
# Pour améliorer le dictionnaire, allez sur http://www.dicollecte.org/



SET UTF-8

WORDCHARS -’'1234567890.




|

|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MP