|
| 1 | +class stringsimilarity { |
| 2 | + |
| 3 | + ; --- Static Methods --- |
| 4 | + compare(param_string1, param_string2) { |
| 5 | + vCount := 0 |
| 6 | + ;make default key value 0 instead of a blank string |
| 7 | + l_arr := {base:{__Get:func("abs").bind(0)}} |
| 8 | + loop, % vCount1 := strLen(param_string1) - 1 { |
| 9 | + l_arr["z" subStr(param_string1, A_Index, 2)]++ |
| 10 | + } |
| 11 | + loop, % vCount2 := strLen(param_string2) - 1 { |
| 12 | + if (l_arr["z" subStr(param_string2, A_Index, 2)] > 0) { |
| 13 | + l_arr["z" subStr(param_string2, A_Index, 2)]-- |
| 14 | + vCount++ |
| 15 | + } |
| 16 | + } |
| 17 | + vSDC := round((2 * vCount) / (vCount1 + vCount2), 2) |
| 18 | + ;round to 0 if less than 0.005 |
| 19 | + if (!vSDC || vSDC < 0.005) { |
| 20 | + return 0 |
| 21 | + } |
| 22 | + ; return 1 if rounded to 1.00 |
| 23 | + if (vSDC = 1) { |
| 24 | + return 1 |
| 25 | + } |
| 26 | + return vSDC |
| 27 | + } |
| 28 | + |
| 29 | + |
| 30 | + rate(param_array, param_string, param_function:="") { |
| 31 | + if (!isObject(param_array)) { |
| 32 | + throw exception("Expected object", -1) |
| 33 | + } |
| 34 | + |
| 35 | + ; Score each option and save into a new array |
| 36 | + l_arr := [] |
| 37 | + for key, value in param_array { |
| 38 | + ; functor |
| 39 | + if (this._internal_isFunction(param_function)) { |
| 40 | + value := param_function.call(value, key, param_array, param_string) |
| 41 | + } |
| 42 | + l_arr[A_Index, "rating"] := this.compare(param_string, value) |
| 43 | + l_arr[A_Index, "target"] := value |
| 44 | + } |
| 45 | + |
| 46 | + ;sort the rated array |
| 47 | + l_sortedArray := this._internal_Sort2DArrayFast(l_arr, "rating") |
| 48 | + ; create the besMatch property and final object |
| 49 | + l_object := {bestMatch: l_sortedArray[1].clone(), ratings: l_sortedArray} |
| 50 | + return l_object |
| 51 | + } |
| 52 | + |
| 53 | + |
| 54 | + closestMatch(param_array, param_string, param_function:="") { |
| 55 | + if (!IsObject(param_array)) { |
| 56 | + throw exception("Expected object", -1) |
| 57 | + } |
| 58 | + l_highestRating := 0 |
| 59 | + |
| 60 | + for key, value in param_array { |
| 61 | + ; functor |
| 62 | + if (this._internal_isFunction(param_function)) { |
| 63 | + value := param_function.call(value, key, param_array, param_string) |
| 64 | + } |
| 65 | + l_rating := this.compare(param_string, value) |
| 66 | + if (l_highestRating < l_rating) { |
| 67 | + l_highestRating := l_rating |
| 68 | + l_bestMatchValue := value |
| 69 | + } |
| 70 | + } |
| 71 | + return l_bestMatchValue |
| 72 | + } |
| 73 | + |
| 74 | + ; --- Intertal Methods --- |
| 75 | + _internal_isFunction(param) { |
| 76 | + fn := numGet(&(_ := Func("InStr").bind()), "Ptr") |
| 77 | + return (isFunc(param) || (isObject(param) && (numGet(¶m, "Ptr") = fn))) |
| 78 | + } |
| 79 | + |
| 80 | + _internal_Sort2DArrayFast(param_arr, param_key) |
| 81 | + { |
| 82 | + for index, obj in param_arr { |
| 83 | + out .= obj[param_key] "+" index "|" |
| 84 | + ; "+" allows for sort to work with just the value |
| 85 | + ; out will look like: value+index|value+index| |
| 86 | + } |
| 87 | + |
| 88 | + v := param_arr[param_arr.minIndex(), param_key] |
| 89 | + if v is number |
| 90 | + type := " N " |
| 91 | + out := subStr(out, 1, strLen(out) -1) ; remove trailing | |
| 92 | + sort, out, % "D| " type " R" |
| 93 | + l_arr := [] |
| 94 | + loop, parse, out, | |
| 95 | + l_arr.push(param_arr[subStr(A_LoopField, inStr(A_LoopField, "+") + 1)]) |
| 96 | + return l_arr |
| 97 | + } |
| 98 | +} |
0 commit comments