cmpstr
Version:
CmpStr is a lightweight, fast and well performing package for calculating string similarity
64 lines (60 loc) • 1.89 kB
JavaScript
// CmpStr v3.2.2 build-bb61120-260311 by Paul Köhler @komed3 / MIT License
;
var Pool = require('../utils/Pool.cjs');
var Metric = require('./Metric.cjs');
class JaroWinklerDistance extends Metric.Metric {
constructor(a, b, opt = {}) {
super('jaroWinkler', a, b, opt, true);
}
compute(a, b, m, n) {
const [matchA, matchB] = Pool.Pool.acquireMany('int32', [m, n]);
try {
for (let i = 0; i < m; i++) matchA[i] = 0;
for (let i = 0; i < n; i++) matchB[i] = 0;
const matchWindow = Math.max(0, Math.floor(n / 2) - 1);
let matches = 0;
for (let i = 0; i < m; i++) {
const start = Math.max(0, i - matchWindow);
const end = Math.min(i + matchWindow + 1, n);
for (let j = start; j < end; j++) {
if (!matchB[j] && a[i] === b[j]) {
matchA[i] = 1;
matchB[j] = 1;
matches++;
break;
}
}
}
let transpos = 0,
jaro = 0,
prefix = 0,
res = 0;
if (matches > 0) {
let k = 0;
for (let i = 0; i < m; i++) {
if (matchA[i]) {
while (!matchB[k]) k++;
if (a[i] !== b[k]) transpos++;
k++;
}
}
transpos /= 2;
jaro = (matches / m + matches / n + (matches - transpos) / matches) / 3;
for (let i = 0; i < Math.min(4, m, n); i++) {
if (a[i] === b[i]) prefix++;
else break;
}
res = jaro + prefix * 0.1 * (1 - jaro);
}
return {
res: Metric.Metric.clamp(res),
raw: { matchWindow, matches, transpos, jaro, prefix }
};
} finally {
Pool.Pool.release('int32', matchA, m);
Pool.Pool.release('int32', matchB, n);
}
}
}
Metric.MetricRegistry.add('jaroWinkler', JaroWinklerDistance);
exports.JaroWinklerDistance = JaroWinklerDistance;