pak/distance.go

62 lines
1.2 KiB
Go

package main
import "math"
func Jaro(a, b string) float64 {
la := float64(len(a))
lb := float64(len(b))
// match range = max(len(a), len(b)) / 2 - 1
matchRange := int(math.Floor(math.Max(la, lb)/2.0)) - 1
matchRange = int(math.Max(0, float64(matchRange-1)))
var matches, halfs float64
transposed := make([]bool, len(b))
for i := 0; i < len(a); i++ {
start := int(math.Max(0, float64(i-matchRange)))
end := int(math.Min(lb-1, float64(i+matchRange)))
for j := start; j <= end; j++ {
if transposed[j] {
continue
}
if a[i] == b[j] {
if i != j {
halfs++
}
matches++
transposed[j] = true
break
}
}
}
if matches == 0 {
return 0
}
transposes := math.Floor(float64(halfs / 2))
return ((matches / la) + (matches / lb) + (matches-transposes)/matches) / 3.0
}
func JaroWinkler(a, b string, boostThreshold float64, prefixSize int) float64 {
j := Jaro(a, b)
if j <= boostThreshold {
return j
}
prefixSize = int(math.Min(float64(len(a)), math.Min(float64(prefixSize), float64(len(b)))))
var prefixMatch float64
for i := 0; i < prefixSize; i++ {
if a[i] == b[i] {
prefixMatch++
}
}
return j + 0.1*prefixMatch*(1.0-j)
}