packages/contributors-view/src/helpers/similarity.ts
/*
* Copyright (C) 2022 SensibleMetrics, Inc. (http://sensiblemetrics.io/)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// import-conductor-skip
/**
* Compares two strings and returns the Levenshtein distance
* @see https://stackoverflow.com/a/36566052/6942210
* @param s1 Text string
* @param s2 text string
*/
export const similarity = (s1: string, s2: string) => {
let longer = s1
let shorter = s2
if (s1.length < s2.length) {
longer = s2
shorter = s1
}
const longerLength = longer.length
if (longerLength === 0) {
return 1.0
}
return (longerLength - editDistance(longer, shorter)) / longerLength
}
const editDistance = (s1: string, s2: string) => {
s1 = s1.toLowerCase()
s2 = s2.toLowerCase()
const costs = new Array<number>()
for (let i = 0; i <= s1.length; i++) {
let lastValue = i
for (let j = 0; j <= s2.length; j++) {
if (i === 0) {
costs[j] = j
} else {
if (j > 0) {
let newValue = costs[j - 1]
if (s1.charAt(i - 1) !== s2.charAt(j - 1)) {
newValue = Math.min(Math.min(newValue, lastValue), costs[j]) + 1
}
costs[j - 1] = lastValue
lastValue = newValue
}
}
}
if (i > 0) {
costs[s2.length] = lastValue
}
}
return costs[s2.length]
}