UNPKG

symspell-ex

Version:

Spelling correction & Fuzzy search based on symmetric delete spelling correction algorithm

93 lines (92 loc) 3.53 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DamerauLevenshteinDistance = void 0; class DamerauLevenshteinDistance { constructor() { this.name = 'DamerauLevenshtein'; // Cache the codes and score arrays to significantly speed up damlev calls: // there's no need to re-allocate them. this.sourceCodes = new Array(32); this.targetCodes = new Array(32); this.score = new Array(33 * 33); } /** * growArray will return an array that's at least as large as the provided * size. It may or may not return the same array that was passed in. * @param {Array} arr * @param {Number} size * @return {Array} */ growArray(arr, size) { if (size <= arr.length) { return arr; } let target = arr.length; while (target < size) { target *= 2; } return new Array(target); } /** * Returns the edit distance between the source and target strings. * @param {String} source * @param {String} target * @return {Number} */ calculateDistance(source, target) { // If one of the strings is blank, returns the length of the other (the // cost of the n insertions) if (!source) { return target.length; } else if (!target) { return source.length; } const sourceLength = source.length; const targetLength = target.length; let i; // Initialize a char code cache array this.sourceCodes = this.growArray(this.sourceCodes, sourceLength); this.targetCodes = this.growArray(this.targetCodes, targetLength); for (i = 0; i < sourceLength; i++) { this.sourceCodes[i] = source.charCodeAt(i); } for (i = 0; i < targetLength; i++) { this.targetCodes[i] = target.charCodeAt(i); } // Initialize the scoring matrix const INF = sourceLength + targetLength; const rowSize = sourceLength + 1; this.score = this.growArray(this.score, (sourceLength + 1) * (targetLength + 1)); this.score[0] = INF; for (i = 0; i <= sourceLength; i++) { this.score[(i + 1) * rowSize] = INF; this.score[(i + 1) * rowSize + 1] = i; } for (i = 0; i <= targetLength; i++) { this.score[i] = INF; this.score[1 * rowSize + i + 1] = i; } // Run the damlev algorithm let chars = {}; let j, DB, i1, j1, j2, newScore; for (i = 1; i <= sourceLength; i += 1) { DB = 0; for (j = 1; j <= targetLength; j += 1) { i1 = chars[this.targetCodes[j - 1]] || 0; j1 = DB; if (this.sourceCodes[i - 1] == this.targetCodes[j - 1]) { newScore = this.score[i * rowSize + j]; DB = j; } else { newScore = Math.min(this.score[i * rowSize + j], Math.min(this.score[(i + 1) * rowSize + j], this.score[i * rowSize + j + 1])) + 1; } this.score[(i + 1) * rowSize + j + 1] = Math.min(newScore, this.score[i1 * rowSize + j1] + (i - i1) + (j - j1 - 1)); } chars[this.sourceCodes[i - 1]] = i; } return this.score[(sourceLength + 1) * rowSize + targetLength + 1]; } } exports.DamerauLevenshteinDistance = DamerauLevenshteinDistance;