Simple fuzzy string matching: returns up to `max` candidates from `options` that share a common substring with `query`, sorted by edit-distance-like score.
(query: &str, options: &[String], max: usize)
| 2080 | /// Simple fuzzy string matching: returns up to `max` candidates from `options` |
| 2081 | /// that share a common substring with `query`, sorted by edit-distance-like score. |
| 2082 | fn fuzzy_match(query: &str, options: &[String], max: usize) -> Vec<String> { |
| 2083 | let query_lower = query.to_lowercase(); |
| 2084 | let mut scored: Vec<(usize, &String)> = options |
| 2085 | .iter() |
| 2086 | .filter_map(|opt| { |
| 2087 | let opt_lower = opt.to_lowercase(); |
| 2088 | // Score: length of longest common substring (simple heuristic) |
| 2089 | let score = longest_common_substring_len(&query_lower, &opt_lower); |
| 2090 | if score >= 2 || opt_lower.contains(&query_lower) || query_lower.contains(&opt_lower) { |
| 2091 | Some((score, opt)) |
| 2092 | } else { |
| 2093 | None |
| 2094 | } |
| 2095 | }) |
| 2096 | .collect(); |
| 2097 | |
| 2098 | // Sort descending by score |
| 2099 | scored.sort_by(|a, b| b.0.cmp(&a.0)); |
| 2100 | scored |
| 2101 | .into_iter() |
| 2102 | .take(max) |
| 2103 | .map(|(_, s)| s.clone()) |
| 2104 | .collect() |
| 2105 | } |
| 2106 | |
| 2107 | /// Length of the longest common substring between two strings. |
| 2108 | fn longest_common_substring_len(a: &str, b: &str) -> usize { |
no test coverage detected