Index: compile_rules_graph.py ================================================================== --- compile_rules_graph.py +++ compile_rules_graph.py @@ -99,10 +99,11 @@ self.dOptPriority = dOptPriority self.dAntiPatterns = {} self.dActions = {} self.dFuncName = {} self.dFunctions = {} + self.dURL = {} def _genTokenLines (self, sTokenLine): "tokenize a string and return a list of lines of tokens" lTokenLines = [] for sTokBlock in sTokenLine.split(): @@ -180,11 +181,11 @@ return lToken def createGraphAndActions (self, lRuleLine): "create a graph as a dictionary with " fStartTimer = time.time() - print("{:>8,} rules in {:<30} ".format(len(lRuleLine), "<"+self.sGraphName+"|"+self.sGraphCode+">"), end="") + print("{:>8,} rules in {:<30} ".format(len(lRuleLine), f"<{self.sGraphName}|{self.sGraphCode}>"), end="") lPreparedRule = [] for i, sRuleName, sTokenLine, iActionBlock, lActions, nPriority in lRuleLine: for aRule in self.createRule(i, sRuleName, sTokenLine, iActionBlock, lActions, nPriority): lPreparedRule.append(aRule) # Debugging @@ -235,11 +236,11 @@ # Parse actions for iAction, (iActionLine, sAction) in enumerate(lActions, 1): sAction = sAction.strip() if sAction: - sActionId = self.sGraphCode + "__" + sRuleName + "__b" + str(iActionBlock) + "_a" + str(iAction) + sActionId = f"{self.sGraphCode}__{sRuleName}__b{iActionBlock}_a{iAction}" aAction = self.createAction(sActionId, sAction, nPriority, len(lToken), dPos, iActionLine) if aAction: sActionName = self.storeAction(sActionId, aAction) lResult = list(lToken) lResult.extend(["##"+str(iLine), sActionName]) @@ -246,17 +247,21 @@ #if iLine == 13341: # print(" ".join(lToken)) # print(sActionId, aAction) yield lResult else: - print(" # Error on action at line:", iLine) + print("# Error on action at line:", iLine) print(sTokenLine, "\n", lActions) + exit() else: print("No action found for ", iActionLine) + exit() def createAction (self, sActionId, sAction, nPriority, nToken, dPos, iActionLine): "create action rule as a list" + sLineId = "#" + str(iActionLine) + # Option sOption = False m = re.match("/(\\w+)/", sAction) if m: sOption = m.group(1) @@ -265,12 +270,12 @@ nPriority = self.dOptPriority.get(sOption, 4) # valid action? m = re.search(r"(?P[-=~/!>])(?P-?\d+\.?|)(?P:\.?-?\d+|)(?P:|)>>", sAction) if not m: - print("\n# Error. No action found at: ", sActionId) - return None + print("\n# Error. No action found at: ", sLineId, sActionId) + exit() # Condition sCondition = sAction[:m.start()].strip() if sCondition: sCondition = changeReferenceToken(sCondition, dPos) @@ -291,11 +296,11 @@ if not m.group("start"): iStartAction = 1 iEndAction = 0 else: if cAction != "-" and (m.group("start").endswith(".") or m.group("end").startswith(":.")): - print("\n# Error. Wrong selection on tokens.", sActionId) + print("\n# Error. Wrong selection on tokens at: ", sLineId ,sActionId) return None if m.group("start").endswith("."): cStartLimit = ">" iStartAction = int(m.group("start").rstrip(".")) if not m.group("end"): @@ -317,11 +322,11 @@ ## error iMsg = sAction.find(" # ") if iMsg == -1: sMsg = "# Error. Error message not found." sURL = "" - print("\n" + sMsg + " Action id: " + sActionId) + print("\n" + sMsg + " at: ", sLineId, sActionId) else: sMsg = sAction[iMsg+3:].strip() sAction = sAction[:iMsg].strip() sURL = "" mURL = re.search("[|] *(https?://.*)", sMsg) @@ -335,18 +340,17 @@ checkIfThereIsCode(sMsg, sActionId) # checking consistancy checkTokenNumbers(sAction, sActionId, nToken) - sLineId = "#" + str(iActionLine) - if cAction == ">": ## no action, break loop if condition is False return [sLineId, sOption, sCondition, cAction, ""] if not sAction and cAction != "!": - print("\n# Error in action at line <" + sActionId + ">: This action is empty.") + print(f"\n# Error in action at line <{sLineId}/{sActionId}>: This action is empty.") + exit() if sAction[0:1] != "=" and cAction != "=": checkIfThereIsCode(sAction, sActionId) if cAction == "-": @@ -354,11 +358,12 @@ if sAction[0:1] == "=": sAction = self.createFunction("sugg", sAction, True) elif sAction.startswith('"') and sAction.endswith('"'): sAction = sAction[1:-1] if not sMsg: - print("\n# Error in action at line <" + sActionId + ">: The message is empty.") + print(f"\n# Error in action at line <{sLineId}/{sActionId}>: The message is empty.") + exit() return [sLineId, sOption, sCondition, cAction, sAction, iStartAction, iEndAction, cStartLimit, cEndLimit, bCaseSensitivity, nPriority, sMsg, sURL] if cAction == "~": ## text processor if sAction[0:1] == "=": sAction = self.createFunction("tp", sAction, True) @@ -366,24 +371,25 @@ sAction = sAction[1:-1] elif sAction not in "␣*_": nToken = sAction.count("|") + 1 if iStartAction > 0 and iEndAction > 0: if (iEndAction - iStartAction + 1) != nToken: - print("\n# Error in action at line <" + sActionId + ">: numbers of modified tokens modified.") + print(f"\n# Error in action at line <{sLineId}/{sActionId}>: numbers of modified tokens modified.") elif iStartAction < 0 or iEndAction < 0 and iStartAction != iEndAction: - print("\n# Warning in action at line <" + sActionName + ">: rewriting with possible token position modified.") + print(f"\n# Warning in action at line <{sLineId}/{sActionId}>: rewriting with possible token position modified.") return [sLineId, sOption, sCondition, cAction, sAction, iStartAction, iEndAction, bCaseSensitivity] if cAction in "!/": ## tags return [sLineId, sOption, sCondition, cAction, sAction, iStartAction, iEndAction] if cAction == "=": ## disambiguator if "define(" in sAction and not re.search(r"define\(\\-?\d+ *, *\[.*\] *\)", sAction): - print("\n# Error in action at line <" + sActionId + ">: second argument for must be a list of strings") + print(f"\n# Error in action at line <{sLineId}/{sActionId}>: second argument for must be a list of strings") + exit() sAction = self.createFunction("da", sAction) return [sLineId, sOption, sCondition, cAction, sAction] - print("\n# Unknown action.", sActionId) + print("\n# Unknown action at ", sLineId, sActionId) return None def storeAction (self, sActionId, aAction): "store in avoiding duplicates and return action name" nVar = 1 @@ -434,14 +440,14 @@ sParams = "lToken, nTokenOffset, nLastToken" else: print("# Unknown function type in [" + sFuncName + "]") continue # Python - sPyCallables += "def {} ({}):\n".format(sFuncName, sParams) - sPyCallables += " return " + sReturn + "\n" + sPyCallables += f"def {sFuncName} ({sParams}):\n" + sPyCallables += f" return {sReturn}\n" # JavaScript - sJSCallables += " {}: function ({})".format(sFuncName, sParams) + " {\n" + sJSCallables += f" {sFuncName}: function ({sParams}) {{\n" sJSCallables += " return " + jsconv.py2js(sReturn) + ";\n" sJSCallables += " },\n" return sPyCallables, sJSCallables @@ -479,11 +485,11 @@ m = re.match(r"@@@@GRAPH: *(\w+) *[|] *(\w+)", sLine.strip()) if m: sGraphName = m.group(1) sGraphCode = m.group(2) if sGraphName in dAllGraph or sGraphCode in dGraphCode: - print("Error at line " + iLine + ". Graph name <" + sGraphName + "> or graph code <" + sGraphCode + "> already exists.") + print(f"Error at line {iLine}. Graph name <{sGraphName}> or graph code <{sGraphCode}> already exists.") exit() dAllGraph[sGraphName] = [] dGraphCode[sGraphName] = sGraphCode else: print("Error. Graph name not found at line", iLine) @@ -492,11 +498,11 @@ # new rule group m = re.match("__(\\w+)(!\\d|)__", sLine) if m: sRuleName = m.group(1) if sRuleName in aRuleName: - print("Error at line " + str(iLine) + ". Rule name <" + sRuleName + "> already exists.") + print(f"Error at line {iLine}. Rule name <{sRuleName}> already exists.") exit() aRuleName.add(sRuleName) iActionBlock = 1 nPriority = int(m.group(2)[1:]) if m.group(2) else -1 else: @@ -569,17 +575,33 @@ sGraphName, dGraph, dActions, sPy, sJS = xFuture.result() dAllGraph[sGraphName] = dGraph dAllActions.update(dActions) sPyCallables += sPy sJSCallables += sJS + # create a dictionary of URL + dTempURL = {} + i = 1 + for sKey, lValue in dAllActions.items(): + if lValue[3] == "-": + if lValue[-1]: + if lValue[-1] not in dTempURL: + dTempURL[lValue[-1]] = i + i += 1 + lValue[-1] = i + else: + lValue[-1] = 0 + dURL = { v: k for k, v in dTempURL.items() } # reversing key and values + dURL[0] = "" + # end print(" Total: ", nRule, "rules, ", len(dAllActions), "actions") print(" Build time: {:.2f} s".format(time.time() - fStartTimer)) return { # the graphs describe paths of tokens to actions which eventually execute callables "rules_graphs": str(dAllGraph), "rules_graphsJS": str(dAllGraph), "rules_actions": str(dAllActions), "rules_actionsJS": jsconv.pyActionsToString(dAllActions), + "rules_graph_URL": str(dURL), "graph_callables": sPyCallables, "graph_callablesJS": sJSCallables } Index: gc_core/js/lang_core/gc_engine.js ================================================================== --- gc_core/js/lang_core/gc_engine.js +++ gc_core/js/lang_core/gc_engine.js @@ -9,11 +9,11 @@ ${string} ${regex} ${map} -if(typeof(process) !== 'undefined') { +if (typeof(process) !== 'undefined') { var gc_options = require("./gc_options.js"); var gc_rules = require("./gc_rules.js"); var gc_rules_graph = require("./gc_rules_graph.js"); var cregex = require("./cregex.js"); var text = require("../text.js"); @@ -669,11 +669,11 @@ try { if (bDebug) { console.log(" >TRY: " + sRuleId + " " + sLineId); } 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 ] + // Suggestion [ option, condition, "-", replacement/suggestion/action, iTokenStart, iTokenEnd, cStartLimit, cEndLimit, bCaseSvty, nPriority, sMessage, iURL ] // 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, ">", "" ] @@ -680,18 +680,19 @@ 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 [iTokenStart, iTokenEnd, cStartLimit, cEndLimit, bCaseSvty, nPriority, sMessage, iURL] = 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.gl_get(nErrorStart, -1)) { - this.dError.set(nErrorStart, this._createErrorFromTokens(sWhat, nTokenOffset, nLastToken, nTokenErrorStart, nErrorStart, nErrorEnd, sLineId, sRuleId, bCaseSvty, sMessage, sURL, bShowRuleId, sOption, bContext)); + this.dError.set(nErrorStart, this._createErrorFromTokens(sWhat, nTokenOffset, nLastToken, nTokenErrorStart, nErrorStart, nErrorEnd, sLineId, sRuleId, bCaseSvty, + sMessage, gc_rules_graph.dURL[iURL], bShowRuleId, sOption, bContext)); this.dErrorPriority.set(nErrorStart, nPriority); this.dSentenceError.set(nErrorStart, this.dError.get(nErrorStart)); if (bDebug) { console.log(" NEW_ERROR: ", this.dError.get(nErrorStart)); } Index: gc_core/js/lang_core/gc_rules_graph.js ================================================================== --- gc_core/js/lang_core/gc_rules_graph.js +++ gc_core/js/lang_core/gc_rules_graph.js @@ -10,13 +10,16 @@ var gc_rules_graph = { dAllGraph: ${rules_graphsJS}, - dRule: ${rules_actionsJS} + dRule: ${rules_actionsJS}, + + dURL: ${rules_graph_URL} }; if (typeof(exports) !== 'undefined') { exports.dAllGraph = gc_rules_graph.dAllGraph; exports.dRule = gc_rules_graph.dRule; + exports.dURL = gc_rules_graph.dURL; } Index: gc_core/py/lang_core/gc_engine.py ================================================================== --- gc_core/py/lang_core/gc_engine.py +++ gc_core/py/lang_core/gc_engine.py @@ -586,11 +586,11 @@ 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 ] + # Suggestion [ option, condition, "-", replacement/suggestion/action, iTokenStart, iTokenEnd, cStartLimit, cEndLimit, bCaseSvty, nPriority, sMessage, iURL ] # 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, ">", "" ] @@ -597,18 +597,19 @@ 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 + iTokenStart, iTokenEnd, cStartLimit, cEndLimit, bCaseSvty, nPriority, sMessage, iURL = 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.dError[nErrorStart] = self._createErrorFromTokens(sWhat, nTokenOffset, nLastToken, nTokenErrorStart, nErrorStart, nErrorEnd, sLineId, sRuleId, bCaseSvty, \ + sMessage, _rules_graph.dURL.get(iURL, ""), bShowRuleId, sOption, bContext) self.dErrorPriority[nErrorStart] = nPriority self.dSentenceError[nErrorStart] = self.dError[nErrorStart] if bDebug: echo(" NEW_ERROR: {}".format(self.dError[nErrorStart])) elif cActionType == "~": Index: gc_core/py/lang_core/gc_rules_graph.py ================================================================== --- gc_core/py/lang_core/gc_rules_graph.py +++ gc_core/py/lang_core/gc_rules_graph.py @@ -5,5 +5,7 @@ # generated code, do not edit dAllGraph = ${rules_graphs} dRule = ${rules_actions} + +dURL = ${rules_graph_URL} Index: gc_lang/fr/rules.grx ================================================================== --- gc_lang/fr/rules.grx +++ gc_lang/fr/rules.grx @@ -870,13 +870,13 @@ TEST: il s’est donc tu TEST: Chacun peut l’entendre d’une manière différente et donc on se demande bien ce qui est mesuré dans les réponses. __/virg(virgule_point_fin_dialogue)__ - ([.] » )[a-zéà] @@0 <<- -1>> " », | » " # Ou il faut une virgule (exemple : « Je viens », dit-il). Ou le point est superflu. Ou il faut une majuscule sur le mot suivant. + ([.] » )[a-zéà] @@0 <<- -1>> " », | » " # Ou il faut une virgule (exemple : « Je viens », dit-il). Ou le point est superflu. Ou il faut une majuscule sur le mot suivant. __/virg(virgule_fin_dialogue)__ - (, »,? )[a-zéà] @@0 <<- -1>> " », | » " # Virgule mal placée ou superflue. + (, »,? )[a-zéà] @@0 <<- -1>> " », | » " # Virgule mal placée ou superflue. TEST: « Ça suffit{{. » }}dit-elle. TEST: « J’en ai plus qu’assez{{, » }}dis-je. TEST: {{Julien}} donne-moi le sel. TEST: dès son premier rendez-vous au centre @@ -8121,11 +8121,11 @@ TEST: Elle souffla puissamment dans le {{corps}} de chasse. # cou / coup / coût __conf_coup_cout_cou1__ - [>cou|>coût|>cout] [de|d’] [>baguette|>barre|>bâton|>bec|>bélier|blues|>botte|>boule|>boutoir|>bol|>bite|>cœur|>chaud|>coude|>couteau|>dé|>dent|>déprime|>froid|fil|>foudre|>genou|>grâce|>griffe|>grisou|>gueule|>hache|>hanche|Jarnac|jus|>jeune|>klaxon|>main|maître|maitre|>massue|>marteau|>menton|>nostalgie|>pied|>poing|>poignard|>pouce|>pute|>queue|>rein|>rabot|>savate|>sang|>sabot|>sabre|>sifflet|>soleil|>sonde|>surin|>tête|>théâtre|>tonnerre|>torchon|>trique|>vent|vieux] + [>cou|>coût|>cout] [de|d’] [>baguette|>barre|>bâton|>bec|>bélier|blues|>botte|>boule|>boutoir|>bol|>bite|>cœur|>chaud|>coude|>couteau|>dé|>dent|>déprime|>froid|fil|>filet|>foudre|>genou|>grâce|>griffe|>grisou|>gueule|>hache|>hanche|Jarnac|jus|>jeune|>klaxon|>main|maître|maitre|>massue|>marteau|>menton|>nostalgie|>pied|>poing|>poignard|>pouce|>pute|>queue|>rein|>rabot|>savate|>sang|>sabot|>sabre|>sifflet|>soleil|>sonde|>surin|>tête|>théâtre|>tonnerre|>torchon|>trique|>vent|vieux] [>cou|>coût|>cout] d’ [>éclat|>épée|>état|>épaule|œil|>estoc] [>cou|>coût|>cout] du sort [>cou|>coût|>cout] [dur|durs] <<- /conf/ -1>> coup|coups # Confusion probable. Le coût est le prix d’une chose. Le cou est la partie joignant le tronc à la tête. Pour ce qui frappe, écrivez “coup”. @@ -8622,11 +8622,11 @@ # étant donné que __conf_étant_donné_que__ étant [donner|donnait|donnais] [que|qu’] - <<- /conf/ -2>> donné # Confusion probable. Locution “étant donné que”. + <<- /conf/ -2>> donné # Confusion probable. Locution “étant donné que”.|https://fr.wiktionary.org/wiki/%C3%A9tant_donn%C3%A9_que TEST: étant {{donnait}} qu’il ne sait pas de quoi il parle, ignorons-le. # évidement / évidemment @@ -8664,17 +8664,21 @@ <<- /conf/ -3>> fins # Confusion. Pour évoquer la finalité de quelque chose, écrivez “fin”. [à|a] >seul faim [de|d’] <<- /conf/ -3>> fin # Confusion. Pour évoquer la finalité de quelque chose, écrivez “fin”. + jusqu’ à la faim + <<- /conf/ --1>> fin # Confusion. Pour évoquer la finalité de quelque chose, écrivez “fin”. + >faim de non-recevoir <<- /conf/ -1>> =\1.replace("a", "").replace("A", "") # Confusion. Pour évoquer la finalité de quelque chose, écrivez “fin”. TEST: Elle manifestait son désaccord par une grève de la {{fin}}. TEST: ces enfants avaient une {{fin}} de loup TEST: Œuvrez à des {{faims}} funestes. TEST: il s’est donné bien des peines à seule {{faim}} de monter en grade +TEST: Jusqu’à la {{faim}} il n’aura rien deviné de la vérité TEST: Même {{faim}} de non-recevoir. # faut / faux __conf_faux_faut__ @@ -9450,10 +9454,11 @@ jusqu’ ou par ou d’ ou mais ou ni ou + c’ en [est|était|sera|serait] ou <<- /conf/ --1>> où # Confusion. La conjonction “ou” signale une alternative. Pour évoquer un lieu, un temps ou une situation, écrivez “où”. ou et [comment|que|qui|quand|pourquoi|quel|quels|quelle|quelles] ou et $:R <<- /conf/ -1>> où # Confusion. La conjonction “ou” signale une alternative. Pour évoquer un lieu, un temps ou une situation, écrivez “où”. @@ -9495,10 +9500,11 @@ TEST: depuis la seconde {{ou}} tu as parlé ->> où TEST: depuis le jour {{ou}} il a été blessé. ->> où TEST: nous sommes dans une situation {{ou}} il faut avancer ->> où TEST: j’irai là {{ou}} le vent me portera ->> où TEST: cela peut vouloir dire plusieurs choses : qu’il y a anguille sous roche, ou qu’elles se trouvent dans de bonnes dispositions à notre égard. +TEST: c’en est où ? # pale / pâle __conf_pâle_pale__ [bien|très|trop|si|vraiment|tellement] >pale @@ -14058,11 +14064,11 @@ >conseiller d’ orientation [scolaire|professionnelle] >contrôle [de|d’] routine >convention [récepteur|générateur] >coque [de|d’] noix >corbeille à >pain - >coup [de|d’] [avance|balai|barre|bâton|bec|bélier|bite|blues|bol|botte|boule|boutoir|cœur|chaud|coude|couteau|dé|dent|déprime|éclat|épaule|épée|estoc|État|foudre|fil|froid|genou|grâce|>griffe|grisou|gueule|hache|hanche|jarnac|jeune|jus|klaxon|main|maître|maitre|marteau|massue|nostalgie|œil|patte|pied|poignard|poing|poker|pouce|pute|queue|rabot|rein|sabre|sabot|sang|savate|semonce|sifflet|soleil|surin|tête|théâtre|tonnerre|trique|torchon|vent|vieux] + >coup [de|d’] [avance|balai|barre|bâton|bec|bélier|bite|blues|bol|botte|boule|boutoir|cœur|chaud|coude|couteau|dé|dent|déprime|éclat|épaule|épée|estoc|État|foudre|fil|filet|froid|genou|grâce|>griffe|grisou|gueule|hache|hanche|jarnac|jeune|jus|klaxon|main|maître|maitre|marteau|massue|nostalgie|œil|patte|pied|poignard|poing|poker|pouce|pute|queue|rabot|rein|sabre|sabot|sang|savate|semonce|sifflet|soleil|surin|tête|théâtre|tonnerre|trique|torchon|vent|vieux] >coup [de|d’] baguette ?magique¿ >coup d’ épée dans l’ eau >coup d’ un soir >coup du sort >coureur [de|d’] >jupon @@ -14319,11 +14325,11 @@ >seuil [de|d’] tolérance à la douleur >silo à [>grains|blé] >soldat d’ élite >sonnette d’ alarme >sortie [de|d’] secours - >soue à >cochonne + >soue à >cochon >sujet [de|d’] prédilection >suspension [de|d’] séance >système d’ exploitation >système [de|d’] santé >système D @@ -14337,11 +14343,11 @@ taux [de|d’] [abstention|absorption|alcool|alphabétisation|endettement|inflation|intérêt|imposition|occupation|ouverture|œstrogène|urée|usure|change|cholestérol|cholesterol|glycémie|fécondité|participation|testostérone|TVA] >témoin à charge tenants et aboutissants >ténor du barreau >tête à claques - >tête [de|d’] [linotte|déterré|déterrée|déterrés|déterrées|mule] + >tête [de|d’] [linotte|déterré+ses|mule] >terrain à découvert >tigre à dents [de|d’] sabre >tigre [de|d’] papier ?mâché¿ >tir [de|d’] barrage >tiret d’ incise