UNPKG

talisman

Version:

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

138 lines (104 loc) 5.76 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /** * Talisman keyers/name-power-set * =============================== * * Keyer returning an opinionated power set of what might be the ways to * write the given name so that one can try to perform fuzzy matching on * partial names such as "P. Henry" & "Philip Henry", for instance. */ exports.default = namePowerSet; var _powerSet = require('obliterator/power-set'); var _powerSet2 = _interopRequireDefault(_powerSet); var _uniq = require('lodash/uniq'); var _uniq2 = _interopRequireDefault(_uniq); var _words = require('../tokenizers/words'); var _words2 = _interopRequireDefault(_words); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // TODO: option for full initials? (else if solution involves only abbrev, we skip) // TODO: disallow single token (on option) // TODO: option to skip or not // TODO: possibility to pass tokens rather than a string // TODO: tweak power set token number threshold (heuristic function genre n or n - 1 etc.) // TODO: option to convert to acronym or not // TODO: predicate to know if we acronym or not (like do it only on firstName for instance) // TODO: return sets as strings, not tokens /** * Function expanding token by multiplexing tokens that are not initials. * * @param {array} tokens - List of tokens. * @param {array} */ function expand(tokens) { for (var i = 0, l = tokens.length; i < l; i++) { if (tokens[i].length > 1) tokens[i] = [tokens[i], tokens[i][0]]; } return tokens; } /** * Permutation helper that will expand token possibilities. * * @param {array} code - List of possibly expanded tokens. * @param {array} */ function permutations(code) { var codes = [[]]; for (var i = 0, l = code.length; i < l; i++) { var current = code[i]; if ((typeof current === 'undefined' ? 'undefined' : _typeof(current)) === 'object') { // Doubling the codes for (var j = 0, m = codes.length * (current.length - 1); j < m; j++) { codes.push(codes[j].slice()); } // Filling the codes var offset = codes.length / current.length; for (var _j = 0, k = 0, _m = current.length; _j < _m; _j++) { var encoding = current[_j]; while (k < offset) { codes[k + _j * offset].push(encoding); k++; } k = 0; } } else { for (var _j2 = 0, _m2 = codes.length; _j2 < _m2; _j2++) { codes[_j2].push(current); } } } return codes; } /** * Function returning the name power set. * * @param {string|array} name - Target name. * @param {array} */ function namePowerSet(name) { // If the name is not yet tokenized, we do so if (typeof name === 'string') name = (0, _words2.default)(name); // Gathering items which are the sorted unique tokens of the name var tokens = (0, _uniq2.default)(name).sort(); if (tokens.length < 2) return [tokens]; var pset = [], step = void 0; var iterator = (0, _powerSet2.default)(tokens); while (step = iterator.next(), !step.done) { pset.push(step.value.slice()); }pset = pset.filter(function (set) { return set.length > 1; }).map(expand).map(permutations); var possibilities = []; for (var i = 0, l = pset.length; i < l; i++) { var set = pset[i]; for (var j = 0, m = set.length; j < m; j++) { if (!set[j].every(function (token) { return token.length < 2; })) possibilities.push(set[j]); } } return possibilities; } module.exports = exports['default'];