@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
65 lines (53 loc) • 2.04 kB
JavaScript
import { assert } from "../../assert.js";
import { min3 } from "../../math/min3.js";
import { string_jaro_distance } from "./string_jaro_distance.js";
/**
* Calculate the Jaro-Winkler distance between two strings.
* Useful for sorting and fuzzy matching.
*
* @param {string} first The string to compare
* @param {string} second The string to compare with
* @returns {number} similarity score, higher value means strings are more similar, between 0 and 1
*
* @example
* string_jaro_winkler("Hello", "Hello") === 1
* string_jaro_winkler("apple", "orange") === 0.58
* string_jaro_winkler("how are you?", "are you good?") === 0.74
*/
export function string_jaro_winkler(first, second) {
assert.isString(first, 'first');
assert.isString(second, 'second');
const l1 = first.length;
const l2 = second.length;
if (l1 === 0 && l2 === 0) {
// special case for empty string
return 1;
}
// Calculate the Jaro distance:
const similarity = string_jaro_distance(first, second, l1, l2);
if (similarity === 0) {
// no similarity at all
return 0;
}
// Transform to Jaro-Winkler
// Prefix scale gives more favorable ratings to strings that share common prefixes
const prefix_scale = 0.1;
const prefix = getPrefix(first, second, min3(l1, l2, 4));
return similarity + prefix * prefix_scale * (1 - similarity);
}
/**
* Counts the number of common characters at the beginning of each word up to a maximum of {@link character_limit}
* @param {string} a1 The first string to compare
* @param {string} a2 The second string to compare
* @param {number} character_limit
* @returns {number} number of matching characters from the start of the string, up to limit
*/
function getPrefix(a1, a2, character_limit) {
let p = 0;
for (; p < character_limit; p++) {
if (a1.charAt(p) !== a2.charAt(p)) {
return p;
}
}
return ++p;
}