use unicode_normalization::char::is_combining_mark;
use unicode_normalization::UnicodeNormalization;
#[must_use]
pub fn normalize_text(value: &str) -> String {
if value.is_ascii() {
return collapse_whitespace(&value.to_ascii_lowercase());
}
let stripped: String = value.nfkd().filter(|c| !is_combining_mark(*c)).collect();
collapse_whitespace(&stripped.to_lowercase())
}
fn collapse_whitespace(s: &str) -> String {
s.split_whitespace().collect::<Vec<_>>().join(" ")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ascii_lowercases_and_collapses() {
assert_eq!(normalize_text("Hello World"), "hello world");
assert_eq!(normalize_text(" Foo Bar "), "foo bar");
assert_eq!(normalize_text("UPPER"), "upper");
assert_eq!(normalize_text(""), "");
assert_eq!(normalize_text(" "), "");
}
#[test]
fn strips_accents_on_latin_text() {
assert_eq!(normalize_text("Café"), "cafe");
assert_eq!(normalize_text("JOSÉ"), "jose");
assert_eq!(normalize_text("naïve"), "naive");
assert_eq!(normalize_text("Crème Brûlée"), "creme brulee");
}
#[test]
fn idempotent() {
let once = normalize_text("Héllo WÖRLD");
assert_eq!(normalize_text(&once), once);
}
}