#![allow(clippy::trivial_regex)]
use regex::Regex;
macro_rules! crtpl {
($a:expr, $b:expr) => {
(Regex::new($a).unwrap(), $b)
};
}
lazy_static! {
static ref SINGULAR_LIST: [(Regex, &'static str); 28] = [
crtpl!("(quiz)zes$", "${1}"),
crtpl!("(matr)ices$", "${1}ix"),
crtpl!("(vert|ind)ices$", "${1}ex"),
crtpl!("^(ox)en$", "${1}"),
crtpl!("(alias)es$", "${1}"),
crtpl!("(octop|vir)i$", "${1}us"),
crtpl!("(cris|ax|test)es$", "${1}is"),
crtpl!("(shoe)s$", "${1}"),
crtpl!("(o)es$", "${1}"),
crtpl!("(bus)es$", "${1}"),
crtpl!("([m|l])ice$", "${1}ouse"),
crtpl!("(x|ch|ss|sh)es$", "${1}"),
crtpl!("(m)ovies$", "${1}ovie"),
crtpl!("(s)eries$", "${1}eries"),
crtpl!("([^aeiouy]|qu)ies$", "${1}y"),
crtpl!("([lr])ves$", "${1}f"),
crtpl!("(tive)s$", "${1}"),
crtpl!("(hive)s$", "${1}"),
crtpl!("(li|wi|kni)ves$", "${1}fe"),
crtpl!("(shea|loa|lea|thie)ves$", "${1}f"),
crtpl!("(^analy)ses$", "${1}sis"),
crtpl!("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "${1}${2}sis"),
crtpl!("([ti])a$", "${1}um"),
crtpl!("(n)ews$", "${1}ews"),
crtpl!("(h|bl)ouses$", "${1}ouse"),
crtpl!("(corpse)s$", "${1}"),
crtpl!("(us)es$", "${1}"),
crtpl!("s$", "")
];
static ref PLURAL_LIST: [(Regex, &'static str); 19] = [
crtpl!("(quiz)$", "${1}zes"),
crtpl!("^(ox)$", "${1}en"),
crtpl!("([m|l])ouse$", "${1}ice"),
crtpl!("(matr|vert|ind)ix|ex$", "${1}ices"),
crtpl!("(x|ch|ss|sh)$", "${1}es"),
crtpl!("([^aeiouy]|qu)y$", "${1}ies"),
crtpl!("(hive)$", "${1}s"),
crtpl!("(?:([^f])fe|([lr])f)$", "${1}${2}ves"),
crtpl!("(shea|lea|loa|thie)f$", "${1}ves"),
crtpl!("sis$", "ses"),
crtpl!("([ti])um$", "${1}a"),
crtpl!("(tomat|potat|ech|her|vet)o$", "${1}oes"),
crtpl!("(bu)s$", "${1}ses"),
crtpl!("(alias)$", "${1}es"),
crtpl!("(octop)us$", "${1}i"),
crtpl!("(ax|test)is$", "${1}es"),
crtpl!("(us)$", "${1}es"),
crtpl!("s$", "s"),
crtpl!("$", "s")
];
}
pub fn singularize(word: String) -> String {
for (re, replacement) in SINGULAR_LIST.iter() {
if re.is_match(&word) {
return re.replace_all(&word, *replacement).to_string();
}
}
word
}
pub fn is_plural(word: String) -> bool {
let plural_form = pluralize(word.clone());
if plural_form == word {
return true;
}
false
}
pub fn pluralize(word: String) -> String {
for (re, replacement) in PLURAL_LIST.iter() {
if re.is_match(&word) {
return re.replace_all(&word, *replacement).to_string();
}
}
word
}
#[cfg(test)]
mod tests {
use super::*;
use test_case::test_case;
#[test_case( "user".to_string(), "users".to_string() )]
#[test_case( "user-group".to_string(), "user-groups".to_string() )]
#[test_case( "bus".to_string(), "buses".to_string() )]
#[test_case( "alias".to_string(), "aliases".to_string() )]
fn test_pluralize(word: String, expected: String) {
assert_eq!(pluralize(word), expected);
}
#[test_case( "users".to_string(), "user".to_string() )]
#[test_case( "user-groups".to_string(), "user-group".to_string() )]
#[test_case( "buses".to_string(), "bus".to_string() )]
#[test_case( "aliases".to_string(), "alias".to_string() )]
#[test_case( "fixes".to_string(), "fix".to_string() )]
fn test_singularize(word: String, expected: String) {
assert_eq!(singularize(word), expected);
}
}