...
1 package smetrics
2
3 import (
4 "math"
5 )
6
7
8 func Jaro(a, b string) float64 {
9
10
11 if len(a) == 0 && len(b) == 0 {
12 return 1
13 }
14
15
16
17 if len(a) == 0 || len(b) == 0 {
18 return 0
19 }
20
21
22 la := float64(len(a))
23 lb := float64(len(b))
24 matchRange := int(math.Max(0, math.Floor(math.Max(la, lb)/2.0)-1))
25 matchesA := make([]bool, len(a))
26 matchesB := make([]bool, len(b))
27 var matches float64 = 0
28
29
30
31
32 for i := 0; i < len(a); i++ {
33 start := int(math.Max(0, float64(i-matchRange)))
34 end := int(math.Min(lb-1, float64(i+matchRange)))
35
36 for j := start; j <= end; j++ {
37 if matchesB[j] {
38 continue
39 }
40
41 if a[i] == b[j] {
42 matchesA[i] = true
43 matchesB[j] = true
44 matches++
45 break
46 }
47 }
48 }
49
50
51
52 if matches == 0 {
53 return 0
54 }
55
56
57
58
59 unaligned := 0
60 j := 0
61 for i := 0; i < len(a); i++ {
62 if !matchesA[i] {
63 continue
64 }
65
66 for !matchesB[j] {
67 j++
68 }
69
70 if a[i] != b[j] {
71 unaligned++
72 }
73
74 j++
75 }
76
77
78 transpositions := math.Floor(float64(unaligned / 2))
79
80
81
82
83
84
85 return ((matches / la) + (matches / lb) + ((matches - transpositions) / matches)) / 3.0
86 }
87
View as plain text