UNPKG

cmpstr

Version:

CmpStr is a lightweight, fast and well performing package for calculating string similarity

64 lines (60 loc) 1.89 kB
// CmpStr v3.2.2 build-bb61120-260311 by Paul Köhler @komed3 / MIT License 'use strict'; 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;