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 @@ -395,59 +395,46 @@ echo("DA: " + str(dTokenPos[tWord[0]]["lMorph"])) echo("FSA: " + str(lMorph)) return True -def morph (dTokenPos, tWord, sPattern, bStrict=True, bNoWord=False): - "analyse a tuple (position, word), return True if sPattern in 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 - zPattern = re.compile(sPattern) - if bStrict: - return bool(lMorph) and all(zPattern.search(s) for s in lMorph) - return any(zPattern.search(s) for s in lMorph) - - -def morphex (dTokenPos, tWord, sPattern, sNegPattern, bNoWord=False): +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 - zNegPattern = re.compile(sNegPattern) - if any(zNegPattern.search(s) for s in lMorph): - return False + 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(s) for s in lMorph): + return False # search sPattern zPattern = re.compile(sPattern) return any(zPattern.search(s) for s in lMorph) -def analyse (sWord, sPattern, bStrict=True): - "analyse a word, return True if sPattern in morphologies (disambiguation off)" - lMorph = _oSpellChecker.getMorph(sWord) - if not lMorph: - return False - zPattern = re.compile(sPattern) - if bStrict: - return bool(lMorph) and all(zPattern.search(s) for s in lMorph) - return any(zPattern.search(s) for s in lMorph) - - -def analysex (sWord, sPattern, sNegPattern): +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 - zNegPattern = re.compile(sNegPattern) - if any(zNegPattern.search(s) for s in lMorph): - return False + 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(s) for s in lMorph): + return False # search sPattern zPattern = re.compile(sPattern) return any(zPattern.search(s) for s in lMorph) @@ -1053,12 +1040,10 @@ return False # check negative condition if sNegPattern: if sNegPattern == "*": # all morph must match sPattern - if not lMorph: - return False 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): @@ -1080,12 +1065,10 @@ return False # check negative condition if sNegPattern: if sNegPattern == "*": # all morph must match sPattern - if not lMorph: - return False 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): @@ -1102,12 +1085,10 @@ return False # check negative condition if sNegPattern: if sNegPattern == "*": # all morph must match sPattern - if not lMorph: - return False zPattern = re.compile(sPattern) bResult = all(zPattern.search(sMorph) for sMorph in lMorph) if bResult and bSetMorph: dToken1["lMorph"] = lMorph return bResult Index: gc_lang/fr/rules.grx ================================================================== --- gc_lang/fr/rules.grx +++ gc_lang/fr/rules.grx @@ -450,14 +450,14 @@ M(?:r|gr|me|[.]) [A-ZÉ]([.])(?=\W+[a-zéèêâîïû]) @@$ <<- ~1>> * # Patronyme réduit à une seule lettre __[s](p_prénom_lettre_point_patronyme)__ ([A-ZÉÈÂÎ][\w-]+)[  ]([A-ZÉÈÂ][.][  ]([A-ZÉÈÂ][\w-]+)) @@0,$,$ - <<- morph(\1, ":M[12]", False) and (morph(\3, ":(?:M[12]|V)", False) or not spell(\3)) ~2>> * + <<- morph(\1, ":M[12]") and (morph(\3, ":(?:M[12]|V)") or not spell(\3)) ~2>> * __[s>(p_prénom_lettre_point)__ ([A-ZÉÈÂÎ][\w-]+)[  ]([A-ZÉÈÂ][.]) @@0,$ - <<- morph(\1, ":M[12]", False) and after("^\W+[a-zéèêîïâ]") ~2>> * + <<- morph(\1, ":M[12]") and after("^\W+[a-zéèêîïâ]") ~2>> * # Patronymes composés avec Le/La/Les __[s](p_patronyme_composé_avec_le_la_les)__ [A-ZÉÈÂÎ][\w-]+[-–—]L(?:es?|a) [A-ZÉÈÂÎ][\w-]+ <<- ~>> =\0.replace(" ", "_") @@ -484,11 +484,11 @@ __[s](p_points_suspension_entre_crochets)__ \[…\] <<- ~>> * __[s](p_mot_entre_crochets)__ \[({w_1})\] @@1 <<- \1.isdigit() ~>> * - <<- __else__ and morph(\1, ":G", False) ~>> =" " + \1 + " " + <<- __else__ and morph(\1, ":G") ~>> =" " + \1 + " " <<- __else__ and \1.isalpha() ~>> " _" __[s](points_suspension_entre_parenthèses)__ \(…\) <<- ->> […] # Pour indiquer une troncature de texte, on utilise usuellement des crochets. <<- ~>> * @@ -663,11 +663,11 @@ # Majuscules après un point __[s]/maj(majuscule_après_point)__ ({w_2})[.] ([a-zéàèîçô]\w*) @@0,$ <<- not re.search("(?i)^(?:etc|[A-Z]|chap|cf|fig|hab|litt|circ|coll|r[eé]f|étym|suppl|bibl|bibliogr|cit|op|vol|déc|nov|oct|janv|juil|avr|sept)$", \1) - and morph(\1, ":", False) and morph(\2, ":", False) + and morph(\1, ":") and morph(\2, ":") -2>> =\2.capitalize() # Après un point, une majuscule est généralement requise. TEST: Je suis là. {{viens}}. ->> Viens TEST: Ils sont devenus idiots. {{c}}’est peine perdue. @@ -686,19 +686,19 @@ # virgules manquantes __[i>/virg(virgule_manquante_avant_etc)__ {w_1}( etc[.]) @@$ <<- -1>> , etc. # Avant « etc. », il faut mettre une virgule. __[i>/virg(virgule_manquante_avant_car)__ ({w_1})( car)(?= (?:j[e’]|tu|ils?|nous|vous|elles?|on|les?|l[a’]|ces?|des?|cette|[mts](?:on|a|es))\b) @@0,$ - <<- not morph(\1, ":[DR]", False) -2>> , car + <<- not morph(\1, ":[DR]") -2>> , car # Si « car » est la conjonction de coordination, une virgule est peut-être souhaitable.|http://bdl.oqlf.gouv.qc.ca/bdl/gabarit_bdl.asp?id=3447 __[i>/virg(virgule_manquante_avant_mais)__ ({w_1})( mais)(?= (?:j[e’]|tu|ils?|nous|vous|elles?|on)\b) @@0,$ - <<- not morph(\1, ">(?:[mtscl]es|[nv]os|quels)/", False) -2>> , mais + <<- not morph(\1, ">(?:[mtscl]es|[nv]os|quels)/") -2>> , mais # Si « mais » est la conjonction de coordination, une virgule est souhaitable si elle introduit une nouvelle proposition.|http://bdl.oqlf.gouv.qc.ca/bdl/gabarit_bdl.asp?id=3445 __[i>/virg(virgule_manquante_avant_donc)__ ({w_1})( donc)(?= (?:j[e’]|tu|ils?|elles?|on)\b) @@0,$ - <<- not morph(\1, ":V", False) -2>> , donc + <<- not morph(\1, ":V") -2>> , donc # Si « donc » est la conjonction de coordination, une virgule est souhaitable si elle introduit une nouvelle proposition.|http://bdl.oqlf.gouv.qc.ca/bdl/gabarit_bdl.asp?id=3448 TEST: Un chien, un chat{{ etc.}} ->> , etc. TEST: Je suis fatigué{{ car}} ils ont joué toute la nuit. ->> , car TEST: Je suis fatigué{{ mais}} il a joué toute la nuit. ->> , mais @@ -940,11 +940,11 @@ # Solution prudente : __[i>/typo(typo_apostrophe_manquante_prudence1)!8__ ne ([mtsl] )([aeéiouhyîèêôû][\w-]*) @@3,$ <<- -1>> =\1[:-1]+"’" # Il manque une apostrophe. __[i>/typo(typo_apostrophe_manquante_prudence2)!8__ (?:je|tu|ils?|nous|vous|on|ça|elles?) ([nmtsl] )([aeéiouhyîèêôû][\w-]*) @@*,$ - <<- not option("mapos") and morph(\2, ":V", False) -1>> =\1[:-1]+"’" # Il manque probablement une apostrophe. + <<- not option("mapos") and morph(\2, ":V") -1>> =\1[:-1]+"’" # Il manque probablement une apostrophe. # Solution audacieuse : __[s>/typo(typo_apostrophe_manquante_audace1)!8__ ([ldsncjmtç] )[aeéiouhAEÉIOUHyîèêôûYÎÈÊÔÛ] @@0 <<- option("mapos") and not before("(?i)(?:lettre|caractère|glyphe|dimension|variable|fonction|point) *$") -1>> =\1[:-1]+"’" # Il manque peut-être une apostrophe. @@ -1093,16 +1093,16 @@ ((\d+(?:,\d+[⁰¹²³⁴⁵⁶⁷⁸⁹]?|[⁰¹²³⁴⁵⁶⁷⁸⁹]|)) ?)(?:[kcmµn]?(?:[slgJKΩ]|m[²³]?|Wh?|Hz|dB)|[%‰€$£¥Åℓhj]|min|°C|℃)(?![’']) @@0,0 <<- -1>> "\2 " # Avec une unité de mesure, mettez un espace insécable. __[s]/unit(unit_nbsp_avant_unités2)__ ((\d+(?:,\d+[⁰¹²³⁴⁵⁶⁷⁸⁹]?|[⁰¹²³⁴⁵⁶⁷⁸⁹])) ?)([a-zA-Zµ][a-zA-Z0-9Ωℓ⁰¹²³⁴⁵⁶⁷⁸⁹/·]*) @@0,0,$ - <<- morphex(\3, ";S", ":[VCR]") or mbUnit(\3) or not spell(\3) + <<- morph(\3, ";S", ":[VCR]") or mbUnit(\3) or not spell(\3) -1>> "\2 " # Si “\3” est une unité de mesure, il manque un espace insécable. Si le nombre se rapporte au mot suivant, c’est aussi valable. __[s]/unit(unit_nbsp_avant_unités3)__ ((\d+) )([a-zA-Zµ][a-zA-Z0-9Ωℓ⁰¹²³⁴⁵⁶⁷⁸⁹/·]*)(?![’']) @@0,0,$ - <<- (\2.__len__() > 4 and not spell(\3)) or morphex(\3, ";S", ":[VCR]") or mbUnit(\3) + <<- (\2.__len__() > 4 and not spell(\3)) or morph(\3, ";S", ":[VCR]") or mbUnit(\3) -1>> "\2 " # Si “\3” est une unité de mesure, il manque un espace insécable. Si le nombre se rapporte au mot suivant, c’est aussi valable. TEST: Ça a duré {{3}}µs TEST: Ça a duré {{3,5 }}µs @@ -1136,11 +1136,11 @@ or after(r"^[   ]*(?:[kcmµn]?(?:[slgJKΩ]|m[²³]?|Wh?|Hz|dB)|[%‰€$£¥Åℓhj]|min|°C|℃)(?![\w’'])") ->> =formatNumber(\0) # Formatage des grands nombres. __[s]/num(num_nombre_quatre_chiffres)__ (?> =formatNumber(\1) # Formatage des grands nombres + <<- morph(\2, ";S", ":[VCR]") or mbUnit(\2) -1>> =formatNumber(\1) # Formatage des grands nombres TEST: {{12345}} ->> 12 345 TEST: {{123456}} ->> 123 456 TEST: {{1234567}} ->> 1 234 567 TEST: {{12345678}} ->> 12 345 678 @@ -1192,11 +1192,11 @@ !!!! Redondances !! !! !! __[i]/redon1(redondances_paragraphe)__ ({w_4})[  ,.;!?:].*[  ](\1) @@0,$ - <<- not morph(\1, ":(?:G|V0)|>(?:t(?:antôt|emps|rès)|loin|souvent|parfois|quelquefois|côte|petit|même)/", False) and not \1[0].isupper() + <<- not morph(\1, ":(?:G|V0)|>(?:t(?:antôt|emps|rès)|loin|souvent|parfois|quelquefois|côte|petit|même)/") and not \1[0].isupper() -2>> _ # Dans ce paragraphe, répétition de « \1 » (à gauche). <<- __also__ -1>> _ # Dans ce paragraphe, répétition de « \1 » (à droite). TEST: __redon1__ Tu es son {{avenir}}. Et lui aussi est ton {{avenir}}. TEST: __redon1__ Car parfois il y en a. Mais parfois il n’y en a pas. @@ -1222,11 +1222,11 @@ __> " !" # Erreur de numérisation ? __> " !" # Erreur de numérisation ? + <<- not morph(word(1), ";S") and not morph(word(-1), ":R") ->> " !" # Erreur de numérisation ? TEST: __ocr__ Oh{{ I}} c’est pas formidable ? TEST: __ocr__ Vraiment{{ 1}} Paul n’en savait rien. TEST: __ocr__ Ça prendra 1 h. TEST: __ocr__ Valeur : 1 KHz. @@ -1253,12 +1253,12 @@ ## Casse __[s]/ocr(ocr_casse1)__ [A-ZÉÈÂÊÎÔ]{w_1} <<- \0.istitle() and before(r"(?i)\w") >>> - <<- morphex(\0, ":G", ":M") ->> =\0.lower() # Erreur de numérisation ? Casse improbable. - <<- __else__ and morphex(\0, ":[123][sp]", ":[MNA]|>Est/") ->> =\0.lower() # Erreur de numérisation ? Casse improbable. + <<- morph(\0, ":G", ":M") ->> =\0.lower() # Erreur de numérisation ? Casse improbable. + <<- __else__ and morph(\0, ":[123][sp]", ":[MNA]|>Est/") ->> =\0.lower() # Erreur de numérisation ? Casse improbable. TEST: __ocr__ votre ami la regarde, {{Vous}} ne l’avez pas achetée TEST: __ocr__ pour accommoder son regard, {{La}} lourde forme demeure TEST: __ocr__ parler de Nicole, {{Le}} sommeil ne vient pas. TEST: __ocr__ a fait de toi, Charles, {{Tu}} étais beau quand @@ -1426,11 +1426,11 @@ ### Traits d’union douteux __[i]/tu(tu_trait_union_douteux)__ ({w1})(?:--|—|–)({w1}) @@0,$ - <<- spell(\1+"-"+\2) and analyse(\1+"-"+\2, ":", False) ->> \1-\2 # Trait d’union : un tiret simple suffit. + <<- spell(\1+"-"+\2) and analyse(\1+"-"+\2, ":") ->> \1-\2 # Trait d’union : un tiret simple suffit. TEST: Nous préparons une {{contre–attaque}}. !!!! Nombres: typographie !! @@ -1446,15 +1446,15 @@ !!!! Écritures épicènes invariables !! __[i](d_typo_écriture_épicène_pluriel)__ ({w_1}[éuitsrn])_(?:[nt]|)e_s @@0 - <<- morphex(\1, ":[NAQ]", ":G") =>> define(\1, [":N:A:Q:e:p"]) + <<- morph(\1, ":[NAQ]", ":G") =>> define(\1, [":N:A:Q:e:p"]) __[i](d_typo_écriture_épicène_singulier)__ ({w_2}[éuitsrn])_e @@0 - <<- morph(\1, ":[NAQ]", False) =>> define(\1, [":N:A:Q:e:s"]) + <<- morph(\1, ":[NAQ]") =>> define(\1, [":N:A:Q:e:s"]) !!! !!! !!! Processeur: épuration des signes inutiles et quelques simplifications !! @@ -1473,15 +1473,15 @@ # le, la ou les chose(s) __[i>(p_le_ou_les)__ l[ea] ou les {w_2}([(]s[)]) @@$ <<- ~1>> s __[i](p_le_ou_la)__ l(e ou la|a ou le) {w_2} @@1 <<- ~1>> ’ # les références aux notes -__[i](p_références_aux_notes)__ [a-zéèâàôîù][a-zéèâàôîù-]+(\d+) @@$ <<- not morph(\0, ":", False) ~1>> * +__[i](p_références_aux_notes)__ [a-zéèâàôîù][a-zéèâàôîù-]+(\d+) @@$ <<- not morph(\0, ":") ~1>> * # faux positifs avec adverbes de négation -__[i](p_pas_mal)__ pas mal <<- not morph(word(-1), ":D", False) ~>> * -__[i](p_pas_assez)__ pas assez ({w_2}) @@$ <<- morph(\1, ":A", False) and not morph(word(-1), ":D", False) ~>> * +__[i](p_pas_mal)__ pas mal <<- not morph(word(-1), ":D") ~>> * +__[i](p_pas_assez)__ pas assez ({w_2}) @@$ <<- morph(\1, ":A") and not morph(word(-1), ":D") ~>> * # faux positifs avec «à chez» __[i](p_de_chez_à_chez_pronom)__ de chez \w+ (?:à|jusqu à) chez (?:moi|toi|lui|elles?|eux|nous|vous) <<- ~>> * __[i](p_de_chez)__ (jusqu à|de) chez @@0 <<- ~1>> * @@ -10245,11 +10245,11 @@ !!!! Redondances dans la phrase !! __[i]/redon2(redondances_phrase)__ ({w_4})[ ,].* (\1) @@0,$ - <<- not morph(\1, ":(?:G|V0)|>même/", False) -2>> _ # Dans cette phrase, répétition de « \1 » (à gauche). + <<- not morph(\1, ":(?:G|V0)|>même/") -2>> _ # Dans cette phrase, répétition de « \1 » (à gauche). <<- __also__ -1>> _ # Dans cette phrase, répétition de « \1 » (à droite). TEST: __redon2__ Quelle {{imposture}}, c’est d’un ennui, c’est une {{imposture}}. TEST: __redon2__ ils sont là côte à côte. TEST: __redon2__ Tu avances petit à petit, et tu réussis. @@ -10260,15 +10260,15 @@ !!!! Mots composés !! __[i]/mc(mc_mot_composé)__ ({w2})-({w2}) @@0,$ <<- not \1.isdigit() and not \2.isdigit() - and not morph(\0, ":", False) and not morph(\2, ":G", False) and spell(\1+\2) + and not morph(\0, ":") and not morph(\2, ":G") and spell(\1+\2) ->> \1\2 # Vous pouvez ôter le trait d’union. <<- \2 != "là" and not re.search("(?i)^(?:ex|mi|quasi|semi|non|demi|pro|anti|multi|pseudo|proto|extra)$", \1) - and not \1.isdigit() and not \2.isdigit() and not morph(\2, ":G", False) - and not morph(\0, ":", False) and not spell(\1+\2) + and not \1.isdigit() and not \2.isdigit() and not morph(\2, ":G") + and not morph(\0, ":") and not spell(\1+\2) ->> _ # Mot inconnu du dictionnaire.|http://www.dicollecte.org/dictionary.php?prj=fr&unknownword=on TEST: __mc__ des {{portes-avions}}. @@ -13704,11 +13704,11 @@ TEST: fait pourtant avéré et corroboré par le même sondage. TEST: ce fait rapporté par des témoins au-delà de tout soupçon n’est pas contestable. #__[i]/infi(infi_faire)__ # (f(?:ai|[iî]|er|on)\w+) +({w_2}(?:ée?s?|ez)) @@0,$ -# <<- morph(\1, ">faire/", False) and not before(r"(?i)\b(?:en|[mtsldc]es?|[nv]ous|un) +$") and morphex(\2, ":V", ":M") +# <<- morph(\1, ">faire/") and not before(r"(?i)\b(?:en|[mtsldc]es?|[nv]ous|un) +$") and morph(\2, ":V", ":M") # and not (re.search("(?i)^fait$", \1) and \2.endswith("é")) # and not (re.search("(?i)^faits$", \1) and \2.endswith("és")) # -2>> =suggVerbInfi(@) # Le verbe devrait être à l’infinitif.