|
const maxDistance = 3; |
|
|
|
function editDistance(a, b) { |
|
|
|
|
|
|
|
|
|
|
|
if (Math.abs(a.length - b.length) > maxDistance) return Math.max(a.length, b.length); |
|
|
|
|
|
const d = []; |
|
|
|
|
|
for (let i = 0; i <= a.length; i++) { |
|
d[i] = [i]; |
|
} |
|
|
|
for (let j = 0; j <= b.length; j++) { |
|
d[0][j] = j; |
|
} |
|
|
|
|
|
for (let j = 1; j <= b.length; j++) { |
|
for (let i = 1; i <= a.length; i++) { |
|
let cost = 1; |
|
if (a[i - 1] === b[j - 1]) { |
|
cost = 0; |
|
} else { |
|
cost = 1; |
|
} |
|
d[i][j] = Math.min( |
|
d[i - 1][j] + 1, |
|
d[i][j - 1] + 1, |
|
d[i - 1][j - 1] + cost |
|
); |
|
|
|
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) { |
|
d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1); |
|
} |
|
} |
|
} |
|
|
|
return d[a.length][b.length]; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function suggestSimilar(word, candidates) { |
|
if (!candidates || candidates.length === 0) return ''; |
|
|
|
candidates = Array.from(new Set(candidates)); |
|
|
|
const searchingOptions = word.startsWith('--'); |
|
if (searchingOptions) { |
|
word = word.slice(2); |
|
candidates = candidates.map(candidate => candidate.slice(2)); |
|
} |
|
|
|
let similar = []; |
|
let bestDistance = maxDistance; |
|
const minSimilarity = 0.4; |
|
candidates.forEach((candidate) => { |
|
if (candidate.length <= 1) return; |
|
|
|
const distance = editDistance(word, candidate); |
|
const length = Math.max(word.length, candidate.length); |
|
const similarity = (length - distance) / length; |
|
if (similarity > minSimilarity) { |
|
if (distance < bestDistance) { |
|
|
|
bestDistance = distance; |
|
similar = [candidate]; |
|
} else if (distance === bestDistance) { |
|
similar.push(candidate); |
|
} |
|
} |
|
}); |
|
|
|
similar.sort((a, b) => a.localeCompare(b)); |
|
if (searchingOptions) { |
|
similar = similar.map(candidate => `--${candidate}`); |
|
} |
|
|
|
if (similar.length > 1) { |
|
return `\n(Did you mean one of ${similar.join(', ')}?)`; |
|
} |
|
if (similar.length === 1) { |
|
return `\n(Did you mean ${similar[0]}?)`; |
|
} |
|
return ''; |
|
} |
|
|
|
exports.suggestSimilar = suggestSimilar; |
|
|