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
#![forbid(unsafe_code)]
#![deny(clippy::all)]
use inflector::cases::snakecase;
use std::borrow::Cow;
mod numeral;
pub use numeral::*;
pub fn singularize(word: &str) -> String {
singularize::singularize(word)
}
pub fn pluralize(word: &str, n: usize) -> Cow<'_, str> {
if n == 1 {
Cow::Borrowed(word)
} else {
Cow::Owned(singularize::pluralize(word))
}
}
pub fn normalize(text: &str) -> String {
let norm_text = text.trim_end_matches(|c: char| c.is_ascii_punctuation());
let norm_text = deunicode::deunicode(norm_text);
let norm_text = singularize(&norm_text.to_lowercase());
let norm_text = snakecase::to_snake_case(&norm_text);
if norm_text.is_empty() {
text.to_string()
} else {
norm_text
}
}
pub fn normalized_eq<A, B, T>(a: A, b: B, levenshtein_tolerance: usize) -> bool
where
A: AsRef<str>,
B: IntoIterator<Item = T>,
T: AsRef<str>,
{
let a_normalized = normalize(a.as_ref());
b.into_iter().any(|s| {
distance::damerau_levenshtein(&normalize(s.as_ref()), &a_normalized)
<= levenshtein_tolerance
})
}