1use matchete::{Matcher, Custom, Similarity};
2
3struct LevenshteinMetric;
5
6impl Similarity<String, String> for LevenshteinMetric {
7 fn score(&self, query: &String, candidate: &String) -> f64 {
8 let distance = levenshtein_distance(query, candidate);
9 let max_len = query.len().max(candidate.len());
10 if max_len == 0 { 1.0 } else { 1.0 - (distance as f64 / max_len as f64) }
11 }
12
13 fn exact(&self, query: &String, candidate: &String) -> bool {
14 query == candidate
15 }
16}
17
18struct JaccardMetric;
20
21impl Similarity<String, String> for JaccardMetric {
22 fn score(&self, query: &String, candidate: &String) -> f64 {
23 let query_chars: std::collections::HashSet<char> = query.chars().collect();
24 let candidate_chars: std::collections::HashSet<char> = candidate.chars().collect();
25
26 let intersection = query_chars.intersection(&candidate_chars).count();
27 let union = query_chars.union(&candidate_chars).count();
28
29 if union == 0 { 1.0 } else { intersection as f64 / union as f64 }
30 }
31}
32
33fn levenshtein_distance(a: &str, b: &str) -> usize {
34 let len_a = a.len();
35 let len_b = b.len();
36
37 if len_a == 0 { return len_b; }
38 if len_b == 0 { return len_a; }
39
40 let mut matrix = vec![vec![0; len_b + 1]; len_a + 1];
41
42 for i in 0..=len_a { matrix[i][0] = i; }
43 for j in 0..=len_b { matrix[0][j] = j; }
44
45 for i in 1..=len_a {
46 for j in 1..=len_b {
47 let cost = if a.chars().nth(i - 1) == b.chars().nth(j - 1) { 0 } else { 1 };
48 matrix[i][j] = (matrix[i - 1][j] + 1)
49 .min(matrix[i][j - 1] + 1)
50 .min(matrix[i - 1][j - 1] + cost);
51 }
52 }
53
54 matrix[len_a][len_b]
55}
56
57fn main() {
58 let matcher = Matcher::<String, String>::new()
60 .add(LevenshteinMetric, 0.7) .add(JaccardMetric, 0.3) .threshold(0.5);
63
64 let query = String::from("test");
66 let candidate = String::from("tent");
67
68 println!("Detailed Analysis Example");
70 println!("========================");
71 let analysis = matcher.analyze(&query, &candidate);
72 println!("Query: {}", analysis.query);
73 println!("Candidate: {}", analysis.candidate);
74 println!("Overall score: {:.2}", analysis.score);
75 println!("Exact match: {}", analysis.exact);
76 println!("Is match: {}", matcher.matches(&query, &candidate));
77 println!("Individual metric scores:");
78 for (i, score) in analysis.scores.iter().enumerate() {
79 println!(
80 " Metric {}:\n Raw score: {:.2}\n Weight: {:.2}\n Weighted score: {:.2}",
81 i + 1, score.value, score.weight, score.weighted()
82 );
83 }
84}