UNPKG

talisman

Version:

Straightforward fuzzy matching, information retrieval and NLP building blocks for JavaScript.

227 lines (165 loc) 9.8 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = phonetic; var _deburr = require('lodash/deburr'); var _deburr2 = _interopRequireDefault(_deburr); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Helpers. */ // NOTE: will only squeeze one letter, not more (e.g. AGREEE => AGREE) function squeeze(word) { return word.replace(/(.)\1/g, '$1'); } /** * Rules. */ /** * Talisman phonetics/french/phonetic * =================================== * * Implementation of the "phonetic" algorithm for the French language. * * [Author]: Edouard Bergé * * [Reference]: * http://www.roudoudou.com/phonetic.php */ var FIRST_PREPROCESSING = [[/O[O]+/g, 'OU'], [/SAOU/g, 'SOU'], [/OES/g, 'OS'], [/CCH/g, 'K'], [/CC([IYE])/g, 'KS$1']]; var SECOND_PREPROCESSING = [[/OIN[GT]$/g, 'OIN'], [/E[RS]$/g, 'E'], [/(C|CH)OEU/g, 'KE'], [/MOEU/g, 'ME'], [/OE([UI]+)([BCDFGHJKLMNPQRSTVWXZ])/g, 'E$1$2'], [/^GEN[TS]$/, 'JAN'], [/CUEI/g, 'KEI'], [/([^AEIOUYC])AE([BCDFGHJKLMNPQRSTVWXZ])/g, '$1E$2'], [/AE([QS])/g, 'E$1'], [/AIE([BCDFGJKLMNPQRSTVWXZ])/g, 'AI$1'], [/ANIEM/g, 'ANIM'], [/(DRA|TRO|IRO)P$/, '$1'], [/(LOM)B$/, '$1'], [/(RON|POR)C$/, '$1'], [/PECT$/, 'PET'], [/ECUL$/, 'CU'], [/(CHA|CA|E)M(P|PS)$/, '$1N'], [/(TAN|RAN)G$/, '$1']]; var RULES = [ // YEUX [/([^VO])ILAG/g, '$1IAJ'], [/([^TRH])UIL(AR|E)(.+)/g, '$1UI$2$3'], [/([G])UIL([AEO])/g, '$1UI$2'], [/([NSPM])AIL([AEO])/g, '$1AI$2'], [/DIL(AI|ON|ER|EM)/g, 'DI$1'], [/RILON/g, 'RION'], [/TAILE/g, 'TAIE'], [/GAILET/g, 'GAIET'], [/AIL(A[IR])/g, 'AI$1'], [/OUILA/g, 'OUIA'], [/EIL(AI|AR|ER|EM)/g, 'AI$1'], [/REILET/g, 'RAIET'], [/EILET/g, 'EIET'], [/AILOL/g, 'AIOL'], [/([^AEIOUY])(SC|S)IEM([EA])/g, '$1$2IAM$3'], [/^(SC|S)IEM([EA])/g, '$1IAM$2'], // MP/MB -> NP/NB [/([OAI])MB/g, '$1NB'], [/([OA])MP/g, '$1NP'], [/GEMB/g, 'JANB'], [/EM([BP])/g, 'AN$1'], [/UMBL/g, 'INBL'], [/CIEN/g, 'SIAN'], // K sounds [/^ECEUR/, 'EKEUR'], [/^CH(OG+|OL+|OR+|EU+|ARIS|M+|IRO|ONDR)/, 'K$1'], [/(YN|RI)CH(OG+|OL+|OC+|OP+|OM+|ARIS|M+|IRO|ONDR)/g, '$1K$2'], [/CHS/g, 'CH'], [/CH(AIQ)/g, 'K$1'], [/^ECHO([^UIPY])/, 'EKO$1'], [/ISCH(I|E)/g, 'ISK$1'], [/^ICHT/, 'IKT'], [/ORCHID/g, 'ORKID'], [/ONCHIO/g, 'ONKIO'], [/ACHIA/g, 'AKIA'], [/([^C])ANICH/g, '$1ANIK'], [/OMANIK/g, 'OMANICH'], [/ACHY([^D])/g, 'AKI$1'], [/([AEIOU])C([BDFGJKLMNPQRTVWXZ])/g, '$1K$2'], [/EUCHA/g, 'EKA'], [/YCH(IA|A|O|ED)/g, 'IK$1'], [/([AR])CHEO/g, '$1KEO'], [/RCHES/g, 'RKES'], [/ECHN/g, 'EKN'], [/OCHTO/g, 'OKTO'], [/CHO(RA|NDR|RE)/g, 'KO$1'], [/MACHM/g, 'MAKM'], [/BRONCHO/g, 'BRONKO'], [/LICHO([SC])/g, 'LIKO$1'], // WEUH [/WA/g, 'OI'], [/WO/g, 'O'], [/(?:WI|WHI|WHY)/g, 'OUI'], [/WHA/g, 'OUA'], [/WHO/g, 'OU'], // GUEU, GNEU, JEU etc. [/GNE([STR])/g, 'NIE$1'], [/GNE/g, 'NE'], [/GI/g, 'JI'], [/GNI/g, 'NI'], [/GN(A|OU|UR)/g, 'NI$1'], [/GY/g, 'JI'], [/OUGAIN/g, 'OUGIN'], [/AGEO([LT])/g, 'AJO$1'], [/GEORG/g, 'JORJ'], [/GEO(LO|M|P|G|S|R)/g, 'JEO$1'], [/([NU])GEOT/g, '$1JOT'], [/GEO([TDC])/g, 'JEO$1'], [/GE([OA])/g, 'J$1'], [/GE/g, 'JE'], [/QU?/g, 'K'], [/C[YI]/g, 'SI'], [/CN/g, 'KN'], [/ICM/g, 'IKM'], [/CEAT/g, 'SAT'], [/CE/g, 'SE'], [/C([RO])/g, 'K$1'], [/CUEI/g, 'KEI'], [/CU/g, 'KU'], [/VENCA/g, 'VANSA'], [/C([AS])/g, 'K$1'], [/CLEN/g, 'KLAN'], [/C([LZ])/g, 'K$1'], [/CTIQ/g, 'KTIK'], [/CTI[CS]/g, 'KTIS'], [/CTI([FL])/g, 'KTI$1'], [/CTIO/g, 'KSIO'], [/CT([IUEOR])?/g, 'KT$1'], [/PH/g, 'F'], [/TH/g, 'T'], [/OW/g, 'OU'], [/LH/g, 'L'], [/RDL/g, 'RL'], [/CH(LO|R)/g, 'K$1'], [/PTIA/g, 'PSIA'], [/GU([^RLMBSTPZN])/g, 'G$1'], [/GNO(?=[MLTNRKG])/g, 'NIO'], // TI -> SI [/BUTI([EA])/g, 'BUSI$1'], [/BATIA/g, 'BASIA'], [/ANTIEL/g, 'ANSIEL'], [/RETION/g, 'RESION'], [/ENTI([EA])L/g, 'ENSI$1L'], [/ENTIO/g, 'ENSIO'], [/ENTIAI/g, 'ENSIAI'], [/UJETION/g, 'UJESION'], [/ATIEM/g, 'ASIAM'], [/PETIEN/g, 'PESIEN'], [/CETIE/g, 'CESIE'], [/OFETIE/g, 'OFESIE'], [/IPETI/g, 'IPESI'], [/LBUTION/g, 'LBUSION'], [/BLUTION/g, 'BLUSION'], [/L([EA])TION/g, 'L$1SION'], [/SATIET/g, 'SASIET'], [/(.+)ANTI(AL|O)/g, '$1ANSI$2'], [/(.+)INUTI([^V])/g, '$1INUSI$2'], [/([^O])UTIEN/g, '$1USIEN'], [/([^DE])RATI([E])$/, '$1RASI$2'], [/([^SNEU]|KU|KO|RU|LU|BU|TU|AU)T(IEN|ION)/g, '$1S$2'], // Silent H [/([^CS])H/g, '$1'], [/([EN])SH/g, '$1S'], [/SH/g, 'CH'], // Nasals [/OMT/g, 'ONT'], [/IM([BP])/g, 'IN$1'], [/UMD/g, 'OND'], [/([TRD])IENT/g, '$1IANT'], [/IEN/g, 'IN'], [/YM([UOAEIN])/g, 'IM$1'], [/YM/g, 'IN'], [/AHO/g, 'AO'], [/([FDS])AIM/g, '$1IN'], [/EIN/g, 'AIN'], [/AINS/g, 'INS'], // AIN -> IN [/AIN$/, 'IN'], [/AIN([BTDK])/g, 'IN$1'], // UN -> IN [/([^O])UND/g, '$1IND'], [/([JTVLFMRPSBD])UN([^IAE])/g, '$1IN$2'], [/([JTVLFMRPSBD])UN$/, '$1IN'], [/RFUM$/, 'RFIN'], [/LUMB/g, 'LINB'], // EN -> AN [/([^BCDFGHJKLMNPQRSTVWXZ])EN/g, '$1AN'], [/([VTLJMRPDSBFKNG])EN(?=[BRCTDKZSVN])/g, '$1AN'], [/^EN([BCDFGHJKLNPQRSTVXZ]|CH|IV|ORG|OB|UI|UA|UY)/, 'AN$1'], [/(^[JRVTH])EN([DRTFGSVJMP])/, '$1AN$2'], [/SEN([ST])/g, 'SAN$1'], [/^DESENIV/g, 'DESANIV'], [/([^M])EN(U[IY])/g, '$1AN$2'], [/(.+[JTVLFMRPSBD])EN([JLFDSTG])/g, '$1AN$2'], // EI -> AI [/([VSBSTNRLPM])E[IY]([ACDFRJLGZ])/g, '$1AI$2'], // Ô [/EAU/g, 'O'], [/EU/g, 'E'], [/Y/g, 'I'], [/EOI/g, 'OI'], [/JEA/g, 'JA'], [/OIEM/g, 'OIM'], [/OUANJ/g, 'OUENJ'], [/OUA/g, 'OI'], [/OUENJ/g, 'OUANJ'], [/AU([^E])/g, 'O$1'], // Refining [/^BENJ/, 'BINJ'], [/RTIEL/g, 'RSIEL'], [/PINK/g, 'PONK'], [/KIND/g, 'KOND'], [/KUM(N|P)/g, 'KON$1'], [/LKOU/g, 'LKO'], [/EDBE/g, 'EBE'], [/ARCM/g, 'ARKM'], [/SCH/g, 'CH'], [/^OINI/, 'ONI'], [/([^NDCGRHKO])APT/g, '$1AT'], [/([L]|KON)PT/g, '$1T'], [/OTB/g, 'OB'], [/IXA/g, 'ISA'], [/TG/g, 'G'], [/^TZ/, 'TS'], [/PTIE/g, 'TIE'], [/GT/g, 'T'], [/ANKIEM/g, 'ANKILEM'], [/(LO|RE)KEMAN/g, '$1KAMAN'], [/NT(B|M)/g, 'N$1'], [/GSU/g, 'SU'], [/ESD/g, 'ED'], [/LESKEL/g, 'LEKEL'], [/CK/g, 'K']]; var FIRST_ENDINGS = [[/USIL$/, 'USI'], [/X$|[TD]S$|[DS]$/, ''], [/([^KL]+)T$/, '$1'], // Not really an ending [/^[H]/, '']]; var SECOND_ENDINGS = [[/TIL$/, 'TI'], [/LC$/, 'LK'], [/L[E]?[S]?$/, 'L'], [/(.+)N[E]?[S]?$/, '$1N'], [/EZ$/, 'E'], [/OIG$/, 'OI'], [/OUP$/, 'OU'], [/([^R])OM$/, '$1ON'], [/LOP$/, 'LO'], [/NTANP$/, 'NTAN'], [/TUN$/, 'TIN'], [/AU$/, 'O'], [/EI$/, 'AI'], [/R[DG]$/, 'R'], [/ANC$/, 'AN'], [/KROC$/, 'KRO'], [/HOUC$/, 'HOU'], [/OMAC$/, 'OMA'], [/([J])O([NU])[CG]$/, '$1O$2'], [/([^GTR])([AO])NG$/, '$1$2N'], [/UC$/, 'UK'], [/AING$/, 'IN'], [/([EISOARN])C$/, '$1K'], [/([ABD-MO-Z]+)[EH]+$/, '$1'], [/EN$/, 'AN'], [/(NJ)EN$/, '$1AN'], [/^PAIEM/, 'PAIM'], [/([^NTB])EF$/, '$1']]; /** * Exceptions. */ var EXCEPTIONS = { CD: 'CD', BD: 'BD', BV: 'BV', TABAC: 'TABA', FEU: 'FE', FE: 'FE', FER: 'FER', FIEF: 'FIEF', FJORD: 'FJORD', GOAL: 'GOL', FLEAU: 'FLEO', HIER: 'IER', HEU: 'E', HE: 'E', OS: 'OS', RIZ: 'RI', RAZ: 'RA', // Catching up exceptions placed elsewhere in the original algorithm ECHO: 'EKO' }; var ABBREVIATION_REGEX = /[BCDFGHJKLMNPQRSTVWXYZ][BCDFGHJKLMNPQRSTVWXYZ][BCDFGHJKLMNPQRSTVWXYZ][BCDFGHJKLMNPQRSTVWXYZ]*/; var SIMPLE_WORDS_REGEX = /[RFMLVSPJDF][AEIOU]/; /** * Function taking a single word and computing its phonetic code. * * @param {string} word - The word to process. * @return {string} - The phonetic code. * * @throws {Error} The function expects the word to be a string. */ function phonetic(word) { if (typeof word !== 'string') throw Error('talisman/phonetics/french/phonetic: the given word is not a string.'); // Preparing the word word = word.toUpperCase().replace(/Œ/g, 'OEU').replace(/Æ/g, 'E').replace(/Ç/g, 'S'); word = (0, _deburr2.default)(word).replace(/[^A-Z]/g, ''); var code = word; // First preprocessing for (var i = 0, l = FIRST_PREPROCESSING.length; i < l; i++) { var _FIRST_PREPROCESSING$ = FIRST_PREPROCESSING[i], pattern = _FIRST_PREPROCESSING$[0], replacement = _FIRST_PREPROCESSING$[1]; code = code.replace(pattern, replacement); } // Squeezing code = squeeze(code); // Is the word an exception? var exception = EXCEPTIONS[code]; if (exception) return exception; // Second preprocessing for (var _i = 0, _l = SECOND_PREPROCESSING.length; _i < _l; _i++) { var _SECOND_PREPROCESSING = SECOND_PREPROCESSING[_i], pattern = _SECOND_PREPROCESSING[0], replacement = _SECOND_PREPROCESSING[1]; code = code.replace(pattern, replacement); } // Applying rules for (var _i2 = 0, _l2 = RULES.length; _i2 < _l2; _i2++) { var _RULES$_i = RULES[_i2], pattern = _RULES$_i[0], replacement = _RULES$_i[1]; code = code.replace(pattern, replacement); } // First endings for (var _i3 = 0, _l3 = FIRST_ENDINGS.length; _i3 < _l3; _i3++) { var _FIRST_ENDINGS$_i = FIRST_ENDINGS[_i3], pattern = _FIRST_ENDINGS$_i[0], replacement = _FIRST_ENDINGS$_i[1]; code = code.replace(pattern, replacement); } // Saving the code for very short words var backupCode = code; // Second endings for (var _i4 = 0, _l4 = SECOND_ENDINGS.length; _i4 < _l4; _i4++) { var _SECOND_ENDINGS$_i = SECOND_ENDINGS[_i4], pattern = _SECOND_ENDINGS$_i[0], replacement = _SECOND_ENDINGS$_i[1]; code = code.replace(pattern, replacement); } // Squeezing the code again code = squeeze(code); // Special cases if (code === 'FUEL') code = 'FIOUL'; // If the code is "O" we return it (only acceptable code with only 1 letter) if (code === 'O') return code; // Attempting to save short codes if (code.length < 2) { // Abbreviations if (ABBREVIATION_REGEX.test(word)) return word; if (SIMPLE_WORDS_REGEX.test(word)) { if (word.length === 3 || word.length === 4) return word.slice(0, -1); } if (backupCode.length > 1) return backupCode; } if (code.length > 1) return code; return ''; } module.exports = exports['default'];