UNPKG

real-damerau-levenshtein

Version:

Damerau Levenshtein that actually produces right results.

53 lines (51 loc) 1.97 kB
function dam(str1, str2) { const da = new Uint32Array(0x10000); const getIndex = (rowWidth, x, y) => { return (y + 1) * rowWidth + (x + 1); }; const initializeDPMatrix = (a, b) => { const maxDistance = a.length + b.length; const ROW_WIDTH = a.length + 2; const COL_WIDTH = b.length + 2; const d = new Uint32Array(ROW_WIDTH * COL_WIDTH); d[getIndex(ROW_WIDTH, -1, -1)] = maxDistance; for (let i = 0; i <= a.length; i++) { d[getIndex(ROW_WIDTH, i, -1)] = maxDistance; d[getIndex(ROW_WIDTH, i, 0)] = i; } for (let i = 0; i <= b.length; i++) { d[getIndex(ROW_WIDTH, -1, i)] = maxDistance; d[getIndex(ROW_WIDTH, 0, i)] = i; } return [ROW_WIDTH, d]; }; const calculateStringDistance = (a, b, maxLenght = Math.max(a.length, b.length)) => { if (a.length + b.length === 0 || maxLenght === 0) { return 0; } a = a.length > maxLenght ? a.substring(0, maxLenght) : a; b = b.length > maxLenght ? b.substring(0, maxLenght) : b; const [ROW_WIDTH, d] = initializeDPMatrix(a, b); da.fill(0); for (let i = 1; i <= a.length; i++) { let db = 0; for (let j = 1; j <= b.length; j++) { const k = da[b.charCodeAt(j - 1)]; const l = db; let cost = 1; if (a.charCodeAt(i - 1) === b.charCodeAt(j - 1)) { cost = 0; db = j; } d[getIndex(ROW_WIDTH, i, j)] = Math.min(d[getIndex(ROW_WIDTH, i - 1, j - 1)] + cost, d[getIndex(ROW_WIDTH, i, j - 1)] + 1, d[getIndex(ROW_WIDTH, i - 1, j)] + 1, d[getIndex(ROW_WIDTH, k - 1, l - 1)] + (i - k - 1) + (j - l - 1) + 1); da[a.charCodeAt(i - 1)] = i; } } return d[getIndex(ROW_WIDTH, a.length, b.length)]; }; const steps = calculateStringDistance(str1, str2) const length = Math.max(str1.length, str2.length) const relative = length === 0 ? 0 : (steps / length); const similarity = 1 - relative return { steps, relative, similarity } }