talisman
Version:
Straightforward fuzzy matching, information retrieval and NLP building blocks for JavaScript.
122 lines (102 loc) • 3.46 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.similarity = similarity;
exports.distance = distance;
var _suffixArray = require('mnemonist/suffix-array');
/**
* Abstract indexOf helper needed to find the given subsequence's starting
* index in the given sequence. Note that this function may seem naive
* because it misses cases when, for instance, the subsequence is not found
* but this is of no concern because we use the function in cases when it's
* not possible that the subsequence is not found.
*
* @param {mixed} haystack - Target sequence.
* @param {mixed} needle - Subsequence to find.
* @return {number} - The starting index.
*/
function indexOf(haystack, needle) {
if (typeof haystack === 'string') return haystack.indexOf(needle);
for (var i = 0, j = 0, l = haystack.length, n = needle.length; i < l; i++) {
if (haystack[i] === needle[j]) {
j++;
if (j === n) return i - j + 1;
} else {
j = 0;
}
}
return -1;
}
/**
* Function returning the number of Ratcliff-Obershelp matches. This works
* by finding the LCS of both strings before recursively finding the LCS
* of the substrings both before and after the LCS in the initial strings and
* so on...
*
* @param {mixed} a - The first sequence to process.
* @param {mixed} b - The second sequence to process.
* @return {number} - The number of matches.
*/
/**
* Talisman metrics/ratcliff-obershelp
* ====================================
*
* Function computing the Ratcliff-Obershelp similarity/distance.
*
* [References]:
* https://xlinux.nist.gov/dads/HTML/ratcliffObershelp.html
* http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/DDJ/1988/8807/8807c/8807c.htm
*
* [Articles]:
* PATTERN MATCHING: THE GESTALT APPROACH
* John W. Ratcliff, David E. Metzener
*
* Paul E. Black, "Ratcliff/Obershelp pattern recognition", in Dictionary of
* Algorithms and Data Structures [online], Vreda Pieterse and Paul E. Black,
* eds. 17 December 2004.
*
* [Tags]: string metric.
*/
function matches(a, b) {
var stack = [a, b];
var m = 0;
while (stack.length) {
a = stack.pop();
b = stack.pop();
if (!a.length || !b.length) continue;
var lcs = new _suffixArray.GeneralizedSuffixArray([a, b]).longestCommonSubsequence(),
length = lcs.length;
if (!length) continue;
// Increasing matches
m += length;
// Add to the stack
var aStart = indexOf(a, lcs),
bStart = indexOf(b, lcs);
stack.push(a.slice(0, aStart), b.slice(0, bStart));
stack.push(a.slice(aStart + length), b.slice(bStart + length));
}
return m;
}
/**
* Function returning the Ratcliff-Obershelp similarity between two sequences.
*
* @param {mixed} a - The first sequence to process.
* @param {mixed} b - The second sequence to process.
* @return {number} - The Ratcliff-Obershelp similarity between a & b.
*/
function similarity(a, b) {
if (a === b) return 1;
if (!a.length || !b.length) return 0;
return 2 * matches(a, b) / (a.length + b.length);
}
/**
* Function returning the Ratcliff-Obershelp distance between two sequences.
*
* @param {mixed} a - The first sequence to process.
* @param {mixed} b - The second sequence to process.
* @return {number} - The Ratcliff-Obershelp distance between a & b.
*/
function distance(a, b) {
return 1 - similarity(a, b);
}