UNPKG

talisman

Version:

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

156 lines (134 loc) 7.94 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = fonem; var _deburr = require('lodash/deburr'); var _deburr2 = _interopRequireDefault(_deburr); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } /** * Talisman phonetics/french/fonem * ================================ * * Implementation of the French phonetic algorithm "FONEM" designed to match * family names from Saguenay. * * [Reference]: * http://www.persee.fr/doc/pop_0032-4663_1981_num_36_6_17248 * * [Article]: * Bouchard Gérard, Brard Patrick, Lavoie Yolande. FONEM : Un code de * transcription phonétique pour la reconstitution automatique des familles * saguenayennes. In: Population, 36ᵉ année, n°6, 1981. pp. 1085-1103; */ /** * Constants. */ var VOWELS = 'AEIOUY', CONSONANTS = '^' + VOWELS, V = '[' + VOWELS + ']', C = '[' + CONSONANTS + ']'; /** * Rules. */ var RULES = { // Vowels & vowel clusters 'V-1': [/E?AU/g, 'O'], 'V-2': [/(?:E?AU|O)LT$/, 'O'], 'V-3': [/E?AUT$/, 'O'], 'V-4': [/E?AUX$/, 'O'], 'V-5': [/(?:E?AU|O)LX$/, 'O'], 'V-6': [/E?AUL?D$/, 'O'], 'V-7': [/([^G])AY$/, '$1E'], 'V-8': [/EUX$/, 'EU'], 'V-9': ['EY(?=$|' + C + ')', 'E'], 'V-10': ['(^|' + C + ')Y|Y(' + C + '|$)', '$1I$2'], 'V-11': ['(' + V + ')I(?=' + V + ')', '$1Y'], 'V-12': ['(' + V + ')ILL', '$1Y'], 'V-13': [/OU(?=I(?!LL)|[AEOU])/g, 'W'], 'V-14': ['(' + V + ')\\1', '$1'], // Nasals 'V-15': ['[AE]M(?=[' + CONSONANTS + 'N](?!$))', 'EN'], 'V-16': ['OM(?=[' + CONSONANTS + 'N])', 'ON'], 'V-17': ['AN(?=' + C + ')', 'EN'], 'V-18': ['(?:AIM|AIN|EIN)(?=' + C + '|$)', 'IN'], 'V-19': [/(?:BORNE?|BOURNE?|BURNE)$/, 'BURN'], 'V-20': ['(?:^IM|IM(?=' + C + '))(?=[' + CONSONANTS + 'N])', 'IN'], // Consonants & consonant clusters 'C-1': [/BV/g, 'V'], 'C-2': ['(' + V + ')C(?=[EIY])', '$1SS'], 'C-3': [/([^CX])C(?=[EIY])/g, '$1S'], 'C-4': [/^C(?=[EIY])/, 'S'], 'C-5': [/^C(?=[AOU])/, 'K'], 'C-6': ['(' + V + ')C$', '$1K'], 'C-7': ['C(?=[' + CONSONANTS + 'CH])', 'K'], 'C-8': [/CC(?=[AOU])/g, 'K'], 'C-9': [/CC(?=[EIY])/g, 'X'], 'C-10': [/G(?=[EIY])/g, 'J'], 'C-11': [/GA(?=I?[MN])/g, 'G§'], // The paper is inconsistent so I cheated. 'C-12': [/(?:GEO|GEAU)/g, 'JO'], 'C-13': ['GNI(?=' + V + ')', 'GN'], 'C-14': [/(^|[^CPS])H/g, '$1'], 'C-15': [/JEA/g, 'JA'], 'C-16': ['^MAC(?=' + C + ')', 'M§'], // The paper is inconsistent so I cheated. 'C-17': [/^MC/, 'M§'], 'C-18': [/PH/g, 'F'], 'C-19': [/QU/g, 'K'], 'C-20': [/^SC(?=[EIY])/, 'S'], 'C-21': [/(.)SC(?=[EIY])/g, '$1SS'], 'C-22': [/(.)SC(?=[AOU])/g, '$1SK'], 'C-23': [/SH/g, 'CH'], 'C-24': [/TIA$/, 'SSIA'], 'C-25': [/([AIOUY])W/g, '$1'], 'C-26': [/X[CSZ]/g, 'X'], 'C-27': ['(?:Z(?=' + V + ')|(' + C + ')Z(?=' + C + '))', '$1S'], 'C-28': ['(?:([' + CONSONANTS + 'CLS])\\1|(C)C(?!' + V + ')|(' + C + 'S)S|(.S)S(?!' + V + ')|([^I]L)L)', '$1$2$3$4$5'], 'C-28-bis': [/ILE$/, 'ILLE'], 'C-29': ['(?:(ILS)|([CS]H)|([MN]P)|(R[CFKLNSX])|(' + C + ')' + C + ')$', '$1$2$3$4$5'], 'C-30': [/^(?:SINT?|SAINT?|SEIN|SEIM|CINQ?)/, 'ST-'], 'C-31': [/^SAINTE/, 'STE-'], 'C-32': [/^ST(?!E)/, 'ST-'], 'C-33': [/^STE/, 'STE-'] }; // Compiling rules for (var k in RULES) { var rule = RULES[k]; if (!(rule[0] instanceof RegExp)) rule[0] = new RegExp(rule[0], 'g'); } // Rules must be ordered var ORDERED_RULES = ['V-14', 'C-28', 'C-28-bis', // START 'C-12', 'C-9', 'C-10', 'C-16', 'C-17', 'C-20', 'C-2', 'C-3', 'C-7', 'V-2', 'V-3', 'V-4', 'V-5', 'V-6', 'V-1', 'C-14', 'C-11', 'C-33', 'C-32', 'C-31', 'C-30', // SAINT 'V-15', 'V-17', 'V-18', 'V-7', 'V-8', 'V-9', 'V-10', 'V-11', 'V-12', 'V-13', 'V-16', 'V-19', 'V-20', // V 'C-1', 'C-4', 'C-5', 'C-6', 'C-8', 'C-13', 'C-15', 'C-18', // C 'C-19', 'C-21', 'C-22', 'C-23', 'C-24', 'C-25', 'C-26', 'C-27', // C 'C-29', // END 'V-14', 'C-28', 'C-28-bis' // ONCE AGAIN ].map(function (key) { return RULES[key]; }); var FIXING_RULES = [[/G§/g, 'GA'], [/M§/g, 'MAC']]; /** * Function taking a single name and computing its FONEM code. * * @param {string} name - The name to process. * @return {string} - The FONEM code. * * @throws {Error} The function expects the name to be a string. */ function fonem(name) { if (typeof name !== 'string') throw Error('talisman/phonetics/french/fonem: the given name is not a string.'); var code = (0, _deburr2.default)(name).toUpperCase().replace(/[^A-Z]/, ''); // Applying rules in order for (var i = 0, l = ORDERED_RULES.length; i < l; i++) { var _ORDERED_RULES$i = ORDERED_RULES[i], pattern = _ORDERED_RULES$i[0], replacement = _ORDERED_RULES$i[1]; code = code.replace(pattern, replacement); } // Fixing rules for (var _i = 0, _l = FIXING_RULES.length; _i < _l; _i++) { var _code; code = (_code = code).replace.apply(_code, _toConsumableArray(FIXING_RULES[_i])); }return code; } module.exports = exports['default'];