use regex::{NoExpand, Regex};
use rskit_errors::{AppError, AppResult};
#[derive(Debug, Clone)]
enum RuleMatcher {
Literal(String),
Pattern(Regex),
}
#[derive(Debug, Clone)]
pub struct Rule {
matcher: RuleMatcher,
placeholder: String,
}
impl Rule {
#[must_use]
pub fn literal(text: impl Into<String>, placeholder: impl Into<String>) -> Self {
Self {
matcher: RuleMatcher::Literal(text.into()),
placeholder: placeholder.into(),
}
}
pub fn pattern(pattern: &str, placeholder: impl Into<String>) -> AppResult<Self> {
let regex = Regex::new(pattern).map_err(|err| {
AppError::invalid_input("pattern", "failed to compile normalization pattern")
.with_cause(err)
})?;
Ok(Self {
matcher: RuleMatcher::Pattern(regex),
placeholder: placeholder.into(),
})
}
fn apply(&self, input: &str) -> String {
match &self.matcher {
RuleMatcher::Literal(text) => input.replace(text, &self.placeholder),
RuleMatcher::Pattern(regex) => regex
.replace_all(input, NoExpand(&self.placeholder))
.into_owned(),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct Normalizer {
rules: Vec<Rule>,
}
impl Normalizer {
#[must_use]
pub fn new(rules: Vec<Rule>) -> Self {
Self { rules }
}
#[must_use]
pub fn apply(&self, input: &str) -> String {
self.rules
.iter()
.fold(input.to_owned(), |text, rule| rule.apply(&text))
}
}