1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#![cfg_attr(all(feature = "nightly", test), feature(test))]
extern crate sliding_windows;
#[cfg(all(feature = "nightly", test))] extern crate test;
pub mod algorithms;
pub(crate) mod util;
pub fn fuzzy_match<'a, T, It>(needle: &str, haystack: It) -> Option<T>
where It: IntoIterator<Item = (&'a str, T)>
{
fuzzy_match_with_algorithms::<T, algorithms::SorensenDice, algorithms::Levenshtein, It>(needle, haystack)
}
pub fn fuzzy_match_with_algorithms<'a, T, FST, SND, It>(
needle: &str,
haystack: It) -> Option<T>
where FST: algorithms::SimilarityAlgorithm,
SND: algorithms::SimilarityAlgorithm,
It: IntoIterator<Item = (&'a str, T)>
{
let mut iter = haystack.into_iter().peekable();
if iter.peek().is_none() {
panic!("No haystack provided!")
}
let mut highest_set: Vec<(&str, T)> = Vec::new();
let mut highest_weight = 0f32;
let mut first_algo = FST::new();
for (name, item) in iter {
let weight = first_algo.get_similarity(needle, name);
if weight == highest_weight {
highest_set.push((name, item))
} else if weight > highest_weight {
highest_weight = weight;
highest_set.clear();
highest_set.push((name, item));
}
}
if highest_set.is_empty() {
return None;
} else if highest_set.len() == 1 {
let (_, item) = highest_set.remove(0);
return Some(item);
}
let mut snd_highest_set: Vec<(&str, T)> = Vec::new();
let mut snd_highest_weight = 0f32;
let mut second_algo = SND::new();
for (name, item) in highest_set.drain(..) {
let weight = second_algo.get_similarity(needle, name);
if weight == snd_highest_weight {
snd_highest_set.push((name, item))
} else if weight > highest_weight {
snd_highest_weight = weight;
snd_highest_set.clear();
snd_highest_set.push((name, item));
}
}
if snd_highest_set.is_empty() || snd_highest_set.len() > 1 {
None
} else {
let (_, item) = snd_highest_set.remove(0);
Some(item)
}
}