use unicode_properties::{GeneralCategoryGroup, UnicodeGeneralCategory};
use crate::config::Normalize;
pub fn exact(value: &str) -> String {
value.trim().to_string()
}
pub fn normalized(value: &str, config: &Normalize) -> String {
let mut result = value.trim().to_string();
if config.case_fold {
result = result.to_lowercase();
}
if config.collapse_whitespace {
result = result.split_whitespace().collect::<Vec<_>>().join(" ");
}
if config.strip_trailing_punct {
result = strip_trailing_punct(&result);
}
result
}
fn strip_trailing_punct(value: &str) -> String {
value
.trim_end_matches(|c: char| {
c.is_whitespace() || c.general_category_group() == GeneralCategoryGroup::Punctuation
})
.to_string()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::Normalize;
fn all_on() -> Normalize {
Normalize::default()
}
#[test]
fn exact_trims() {
assert_eq!(exact(" Ok "), "Ok");
}
#[test]
fn normalized_folds_case_punct_and_keeps_single_space() {
let config = all_on();
assert_eq!(normalized("OK.", &config), "ok");
assert_eq!(normalized("OK ", &config), "ok");
assert_eq!(normalized("ok", &config), "ok");
assert_eq!(normalized("O K", &config), "o k");
}
#[test]
fn normalized_strips_localized_trailing_punctuation() {
let config = all_on();
assert_eq!(normalized("Готово…", &config), "готово");
assert_eq!(normalized("Réponse !", &config), "réponse");
assert_eq!(normalized("Дальше »", &config), "дальше");
}
#[test]
fn normalized_keeps_non_punctuation_symbols() {
let config = all_on();
assert_eq!(normalized("Brand™", &config), "brand™");
}
#[test]
fn exact_is_subset_of_normalized() {
let config = all_on();
let a = "Save";
let b = "Save";
assert_eq!(exact(a), exact(b));
assert_eq!(normalized(a, &config), normalized(b, &config));
assert_ne!(exact("OK."), exact("ok"));
assert_eq!(normalized("OK.", &config), normalized("ok", &config));
}
#[test]
fn flags_are_individually_honored() {
let only_case = Normalize {
case_fold: true,
collapse_whitespace: false,
strip_trailing_punct: false,
};
assert_eq!(normalized("OK.", &only_case), "ok.");
let only_punct = Normalize {
case_fold: false,
collapse_whitespace: false,
strip_trailing_punct: true,
};
assert_eq!(normalized("OK.", &only_punct), "OK");
}
}