Index: gc_core/js/tokenizer.js ================================================================== --- gc_core/js/tokenizer.js +++ gc_core/js/tokenizer.js @@ -3,17 +3,16 @@ "use strict"; const helpers = require("resource://grammalecte/helpers.js"); - const aPatterns = { // All regexps must start with ^. "default": [ [/^[   \t]+/, 'SPACE'], - [/^[,.;:!?…«»“”"()/·]+/, 'SEPARATOR'], + [/^[,.;:!?…«»“”‘’"(){}\[\]/·–—]+/, 'SEPARATOR'], [/^(?:https?:\/\/|www[.]|[a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st_]+[@.][a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st_]+[@.])[a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st_.\/?&!%=+*"'@$#-]+/, 'LINK'], [/^[#@][a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st_-]+/, 'TAG'], [/^<[a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st]+.*?>|<\/[a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st]+ *>/, 'HTML'], [/^\[\/?[a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st]+\]/, 'PSEUDOHTML'], [/^&\w+;(?:\w+;|)/, 'HTMLENTITY'], @@ -22,19 +21,19 @@ [/^[a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st]+(?:[’'`-][a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st]+)*/, 'WORD'] ], "fr": [ [/^[   \t]+/, 'SPACE'], - [/^[,.;:!?…«»“”"()/·]+/, 'SEPARATOR'], + [/^[,.;:!?…«»“”‘’"(){}\[\]/·–—]+/, 'SEPARATOR'], [/^(?:https?:\/\/|www[.]|[a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st_]+[@.][a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st_]+[@.])[a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st_.\/?&!%=+*"'@$#-]+/, 'LINK'], [/^[#@][a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st_-]+/, 'TAG'], [/^<[a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st]+.*?>|<\/[a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st]+ *>/, 'HTML'], [/^\[\/?[a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st]+\]/, 'PSEUDOHTML'], [/^&\w+;(?:\w+;|)/, 'HTMLENTITY'], [/^(?:l|d|n|m|t|s|j|c|ç|lorsqu|puisqu|jusqu|quoiqu|qu)['’`]/i, 'ELPFX'], [/^\d\d?[hm]\d\d\b/, 'HOUR'], - [/^\d+(?:er|nd|e|de|ième|ème|eme)\b/, 'ORDINAL'], + [/^\d+(?:er|nd|e|de|ième|ème|eme)s?\b/, 'ORDINAL'], [/^-?\d+(?:[.,]\d+|)/, 'NUM'], [/^[a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st]+(?:[’'`-][a-zA-Zà-öÀ-Ö0-9ø-ÿØ-ßĀ-ʯfi-st]+)*/, 'WORD'] ] } @@ -44,11 +43,11 @@ constructor (sLang) { this.sLang = sLang; if (!aPatterns.hasOwnProperty(sLang)) { this.sLang = "default"; } - this.aRules = aPatterns[sLang]; + this.aRules = aPatterns[this.sLang]; }; * genTokens (sText) { let m; let i = 0; @@ -67,9 +66,19 @@ } } i += nCut; sText = sText.slice(nCut); } + }; + + getSpellingErrors (sText, oDict) { + let aSpellErr = []; + for (let oToken of this.genTokens(sText)) { + if (oToken.sType === 'WORD' && !oDict.isValidToken(oToken.sValue)) { + aSpellErr.push(oToken); + } + } + return aSpellErr; } } exports.Tokenizer = Tokenizer; Index: gc_lang/fr/config.ini ================================================================== --- gc_lang/fr/config.ini +++ gc_lang/fr/config.ini @@ -3,11 +3,11 @@ lang_name = French locales = fr_FR fr_BE fr_CA fr_CH fr_LU fr_MC fr_BF fr_CI fr_SN fr_ML fr_NE fr_TG fr_BJ country_default = FR name = Grammalecte implname = grammalecte -version = 0.5.17.2 +version = 0.5.18 author = Olivier R. provider = Dicollecte link = http://grammalecte.net description = Correcteur grammatical pour le français. extras = README_fr.txt Index: gc_lang/fr/modules-js/lexicographe.js ================================================================== --- gc_lang/fr/modules-js/lexicographe.js +++ gc_lang/fr/modules-js/lexicographe.js @@ -2,13 +2,15 @@ // License: MPL 2 "use strict"; ${string} +${map} const helpers = require("resource://grammalecte/helpers.js"); +const tkz = require("resource://grammalecte/tokenizer.js"); const _dTAGS = new Map ([ [':G', "[mot grammatical]"], [':N', " nom,"], @@ -155,10 +157,34 @@ ["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"], + [';', "point-virgule"], + [',', "virgule"], + ['?', "point d’interrogation"], + ['!', "point d’exclamation"], + ['(', "parenthèse ouvrante"], + [')', "parenthèse fermante"], + ['[', "crochet ouvrante"], + [']', "crochet fermante"], + ['{', "accolade ouvrante"], + ['}', "accolade fermante"], + ['—', "tiret cadratin"], + ['–', "tiret demi-cadratin"], + ['«', "guillemet ouvrant (chevrons)"], + ['»', "guillemet fermant (chevrons)"], + ['“', "guillemet ouvrant double"], + ['”', "guillemet fermant double"], + ['‘', "guillemet ouvrant"], + ['’', "guillemet fermant"], +]); + class Lexicographe { constructor (oDict) { this.oDict = oDict; @@ -165,24 +191,71 @@ this._zElidedPrefix = new RegExp ("^([dljmtsncç]|quoiqu|lorsqu|jusqu|puisqu|qu)['’](.+)", "i"); this._zCompoundWord = new RegExp ("([a-zA-Zà-ö0-9À-Öø-ÿØ-ßĀ-ʯ]+)-((?: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)$", "i"); this._zTag = new RegExp ("[:;/][a-zA-Zà-ö0-9À-Öø-ÿØ-ßĀ-ʯ*][^:;/]*", "g"); }; - analyzeText (sText) { + getInfoForToken (oToken) { + // Token: .sType, .sValue, .nStart, .nEnd + let m = null; + try { + helpers.echo(oToken); + switch (oToken.sType) { + case 'SEPARATOR': + return [oToken.sType, oToken.sValue, _dSeparator._get(oToken.sValue, "caractère indéterminé")]; + break; + case 'NUM': + return [oToken.sType, oToken.sValue, "nombre"]; + break; + case 'LINK': + return [oToken.sType, oToken.sValue.slice(0,40)+"…", "hyperlien"]; + break; + case 'ELPFX': + sTemp = oToken.sValue.replace("’", "'").replace("`", "'").toLowerCase(); + return [oToken.sType, oToken.sValue, _dPFX._get(sTemp, "préfixe élidé inconnu")]; + break; + case 'WORD': + if (oToken.sValue._count("-") > 4) { + return ["COMPLEX", oToken.sValue, "élément complexe indéterminé"]; + } + else if (this.oDict.isValidToken(oToken.sValue)) { + let lMorph = this.oDict.getMorph(oToken.sValue); + let aElem = [ for (s of lMorph) if (s.includes(":")) this._formatTags(s) ]; + return [ oToken.sType, oToken.sValue, [aElem] ]; + } + else if (m = this._zCompoundWord.exec(oToken.sValue)) { + // mots composés + let lMorph = this.oDict.getMorph(m[1]); + let aElem = [ for (s of lMorph) if (s.includes(":")) this._formatTags(s) ]; + aElem.push("-" + m[2] + ": " + this._formatSuffix(m[2].toLowerCase())); + return [ oToken.sType, oToken.sValue, [aElem] ]; + } + else { + return ["INCONNU", oToken.sValue, "inconnu du dictionnaire"]; + } + break; + } + } + catch (e) { + helpers.logerror(e); + } + return null + }; + + getHTMLForText (sText) { sText = sText.replace(/[.,.?!:;…\/()\[\]“”«»"„{}–—#+*<>%=\n]/g, " ").replace(/\s+/g, " "); let iStart = 0; let iEnd = 0; let sHtml = '
\n'; while ((iEnd = sText.indexOf(" ", iStart)) !== -1) { - sHtml += this.analyzeWord(sText.slice(iStart, iEnd)); + sHtml += this.getHTMLForToken(sText.slice(iStart, iEnd)); iStart = iEnd + 1; } - sHtml += this.analyzeWord(sText.slice(iStart)); + sHtml += this.getHTMLForToken(sText.slice(iStart)); return sHtml + '
\n'; - } + }; - analyzeWord (sWord) { + getHTMLForToken (sWord) { try { if (!sWord) { return ""; } if (sWord._count("-") > 4) { @@ -205,13 +278,13 @@ sWord = m2[1]; } // Morphologies let lMorph = this.oDict.getMorph(sWord); if (lMorph.length === 1) { - sHtml += "

" + sWord + " : " + this.formatTags(lMorph[0]) + "

\n"; + sHtml += "

" + sWord + " : " + this._formatTags(lMorph[0]) + "

\n"; } else if (lMorph.length > 1) { - sHtml += "

" + sWord + "

\n"; + sHtml += "

" + sWord + "

\n"; } else { sHtml += '

' + sWord + " : absent du dictionnaire

\n"; } // suffixe d’un mot composé if (m2) { @@ -225,11 +298,11 @@ helpers.logerror(e); return "#erreur"; } }; - formatTags (sTags) { + _formatTags (sTags) { let sRes = ""; sTags = sTags.replace(/V([0-3][ea]?)[itpqnmr_eaxz]+/, "V$1"); let m; while ((m = this._zTag.exec(sTags)) !== null) { sRes += _dTAGS.get(m[0]); Index: gc_lang/fr/xpi/gce_worker.js ================================================================== --- gc_lang/fr/xpi/gce_worker.js +++ gc_lang/fr/xpi/gce_worker.js @@ -84,28 +84,18 @@ return JSON.stringify(aGrammErr); } function parseAndSpellcheck (sText, sLang, bDebug, bContext) { let aGrammErr = gce.parse(sText, sLang, bDebug, bContext); - let aSpellErr = []; - for (let oToken of oTokenizer.genTokens(sText)) { - if (oToken.sType === 'WORD' && !oDict.isValidToken(oToken.sValue)) { - aSpellErr.push(oToken); - } - } + let aSpellErr = oTokenizer.getSpellingErrors(sText, oDict); return JSON.stringify({ aGrammErr: aGrammErr, aSpellErr: aSpellErr }); } function parseAndTag (sText, iParagraph, sLang, bDebug) { sText = text.addHtmlEntities(sText); - let aSpellErr = []; - for (let oToken of oTokenizer.genTokens(sText)) { - if (oToken.sType === 'WORD' && !oDict.isValidToken(oToken.sValue)) { - aSpellErr.push(oToken); - } - } let aGrammErr = gce.parse(sText, sLang, bDebug); + let aSpellErr = oTokenizer.getSpellingErrors(sText, oDict); let sHtml = text.tagParagraph(sText, iParagraph, aGrammErr, aSpellErr); return sHtml; } function parseAndGenerateParagraph (sText, iParagraph, sLang, bDebug) { @@ -156,7 +146,27 @@ // Lexicographer function analyzeWords (sText) { - return oLxg.analyzeText(sText); + getListOfElements(sText); + return oLxg.getHTMLForText(sText); +} + +function getListOfElements (sText) { + try { + helpers.echo("================================================="); + let aElem = []; + let aRes = null; + for (let oToken of oTokenizer.genTokens(sText)) { + aRes = oLxg.getInfoForToken(oToken); + if (aRes) { + helpers.echo(aRes); + aElem = aElem.concat(aRes); + } + } + return JSON.stringify(aElem); + } + catch (e) { + helpers.logerror(e); + } } Index: gc_lang/fr/xpi/package.json ================================================================== --- gc_lang/fr/xpi/package.json +++ gc_lang/fr/xpi/package.json @@ -1,10 +1,10 @@ { "name": "grammalecte-fr", "title": "Grammalecte [fr]", "id": "French-GC@grammalecte.net", - "version": "0.5.17.2", + "version": "0.5.18", "description": "Correcteur grammatical pour le français", "homepage": "http://www.dicollecte.org/grammalecte", "main": "ui.js", "icon": "data/img/icon-48.png", "scripts": {