use crate::{PatternReplace, utils::{build_whole_word_pattern, build_word_pattern, build_optional_whole_word_pattern}, WordBounds, PatternMatch, PatternCapture};
pub trait MatchWord {
fn match_word_bounds(&self, word: &str, bounds: WordBounds, case_insensitive: bool) -> bool;
fn match_word(&self, word: &str, case_insensitive: bool) -> bool;
fn match_any_words(&self, words: &[&str], case_insensitive: bool) -> bool;
fn match_word_start(&self, word: &str, case_insensitive: bool) -> bool;
fn match_word_end(&self, word: &str, case_insensitive: bool) -> bool;
fn match_word_ci(&self, word: &str) -> bool;
fn match_any_words_ci(&self, words: &[&str]) -> bool;
fn match_word_start_ci(&self, word: &str) -> bool;
fn match_word_end_ci(&self, word: &str) -> bool;
fn match_word_cs(&self, word: &str) -> bool;
fn match_any_words_cs(&self, words: &[&str]) -> bool;
fn match_word_start_cs(&self, word: &str) -> bool;
fn match_word_end_cs(&self, word: &str) -> bool;
fn match_words_by_proximity(&self, first: &str, second: &str, min: i16, max: i16, case_insensitive: bool) -> bool;
fn count_matched_words_bounds(&self, words: &[&str], bounds: WordBounds, case_insensitive: bool) -> usize;
fn match_words_bounds(&self, words: &[&str], bounds: WordBounds, case_insensitive: bool) -> bool;
fn match_words(&self, words: &[&str], case_insensitive: bool) -> bool;
fn match_words_ci(&self, words: &[&str]) -> bool;
fn match_words_cs(&self, words: &[&str]) -> bool;
fn match_words_sets_conditional(&self, sets: &[(bool, &str, bool)]) -> bool;
fn match_words_sets_conditional_ci(&self, tuples: &[(bool, &str)]) -> bool;
}
impl MatchWord for str {
fn match_word_bounds(&self, word: &str, bounds: WordBounds, case_insensitive: bool) -> bool {
let word_pattern = bounds.to_pattern(word);
self.pattern_match(&word_pattern, case_insensitive)
}
fn match_word(&self, word: &str, case_insensitive: bool) -> bool {
let pattern = build_whole_word_pattern(word);
self.pattern_match(&pattern, case_insensitive)
}
fn match_word_start(&self, word: &str, case_insensitive: bool) -> bool {
let word_pattern = build_word_pattern(word, WordBounds::Start);
self.pattern_match(&word_pattern, case_insensitive)
}
fn match_word_end(&self, word: &str, case_insensitive: bool) -> bool {
let word_pattern = build_word_pattern(word, WordBounds::End);
self.pattern_match(&word_pattern, case_insensitive)
}
fn match_word_ci(&self, word: &str) -> bool {
self.match_word(word, true)
}
fn match_word_start_ci(&self, word: &str) -> bool {
self.match_word_start(word, true)
}
fn match_word_end_ci(&self, word: &str) -> bool {
self.match_word_end(word, true)
}
fn match_word_cs(&self, word: &str) -> bool {
self.match_word(word, false)
}
fn match_word_start_cs(&self, word: &str) -> bool {
self.match_word_start(word, false)
}
fn match_word_end_cs(&self, word: &str) -> bool {
self.match_word_end(word, false)
}
fn match_words_by_proximity(&self, first: &str, second: &str, min: i16, max: i16, case_insensitive: bool) -> bool {
let word_pattern_1 = build_whole_word_pattern(first);
let word_pattern_2 = build_whole_word_pattern(second);
if let Some((first_first,first_last)) = self.pattern_first_last_matches(&word_pattern_1, case_insensitive) {
if let Some((second_first, second_last)) = self.pattern_first_last_matches(&word_pattern_2, case_insensitive) {
let diff_i64 = second_last.start() as i64 - first_first.end() as i64;
if diff_i64 >= i16::MIN as i64 && diff_i64 <= i16::MAX as i64 {
let diff = diff_i64 as i16;
return diff >= min && diff <= max;
} else if min < 0 {
let diff_2_i64 = first_last.start() as i64 - second_first.end() as i64;
if diff_2_i64 >= i16::MIN as i64 && diff_2_i64 <= i16::MAX as i64 {
let diff_2 = diff_i64 as i16;
return diff_2 >= min && diff_2 <= max;
}
}
}
}
false
}
fn count_matched_words_bounds(&self, words: &[&str], bounds: WordBounds, case_insensitive: bool) -> usize {
let mut num_matched = 0;
for word in words {
let pattern = bounds.to_pattern(word);
if self.pattern_match(&pattern, case_insensitive) {
num_matched += 1;
}
}
num_matched
}
fn match_words_bounds(&self, words: &[&str], bounds: WordBounds, case_insensitive: bool) -> bool {
words.len() == self.count_matched_words_bounds(words, bounds, case_insensitive)
}
fn match_words(&self, words: &[&str], case_insensitive: bool) -> bool {
self.match_words_bounds(words, WordBounds::Both, case_insensitive)
}
fn match_any_words(&self, words: &[&str], case_insensitive: bool) -> bool {
let pattern = build_optional_whole_word_pattern(words);
self.pattern_match(&pattern, case_insensitive)
}
fn match_words_ci(&self, words: &[&str]) -> bool {
self.match_words_bounds(words, WordBounds::Both, true)
}
fn match_any_words_ci(&self, words: &[&str]) -> bool {
let pattern = build_optional_whole_word_pattern(words);
self.pattern_match(&pattern, true)
}
fn match_words_cs(&self, words: &[&str]) -> bool {
self.match_words_bounds(words, WordBounds::Both, false)
}
fn match_any_words_cs(&self, words: &[&str]) -> bool {
let pattern = build_optional_whole_word_pattern(words);
self.pattern_match(&pattern, false)
}
fn match_words_sets_conditional(&self, sets: &[(bool, &str, bool)]) -> bool {
let num_words = sets.len();
let mut num_matched = 0;
for row in sets {
let (is_positive, word, case_insensitive) = *row;
let pattern = build_whole_word_pattern(word);
if self.pattern_match(&pattern, case_insensitive) == is_positive {
num_matched += 1;
}
}
num_matched == num_words
}
fn match_words_sets_conditional_ci(&self, tuples: &[(bool, &str)]) -> bool {
let num_words = tuples.len();
let mut num_matched = 0;
for row in tuples {
let (is_positive, word) = *row;
let pattern = build_whole_word_pattern(word);
if self.pattern_match(&pattern, true) == is_positive {
num_matched += 1;
}
}
num_matched == num_words
}
}
pub trait ReplaceWord {
fn replace_word_bounds(&self, word: &str, replacement: &str, bounds: WordBounds, case_insensitive: bool) -> Self where Self:Sized;
fn replace_word(&self, word: &str, replacement: &str, case_insensitive: bool) -> Self where Self:Sized;
fn replace_word_ci(&self, word: &str, replacement: &str) -> Self where Self:Sized;
fn replace_word_cs(&self, word: &str, replacement: &str) -> Self where Self:Sized;
fn replace_words(&self, pairs: &[(&str, &str)], case_insensitive: bool) -> Self where Self:Sized;
fn replace_words_ci(&self, pairs: &[(&str, &str)]) -> Self where Self:Sized;
fn replace_words_cs(&self, pairs: &[(&str, &str)]) -> Self where Self:Sized;
fn replace_word_sets(&self, pairs: &[(&str, &str, bool)]) -> Self where Self:Sized;
}
impl ReplaceWord for String {
fn replace_word_bounds(&self, word: &str, replacement: &str, bounds: WordBounds, case_insensitive: bool) -> String {
let pattern = build_word_pattern(word, bounds);
self.pattern_replace(&pattern, replacement, case_insensitive)
}
fn replace_word(&self, word: &str, replacement: &str, case_insensitive: bool) -> String {
let pattern = build_whole_word_pattern(word);
self.pattern_replace(&pattern, replacement, case_insensitive)
}
fn replace_word_ci(&self, word: &str, replacement: &str) -> String {
let pattern = build_whole_word_pattern(word);
self.pattern_replace(&pattern, replacement, true)
}
fn replace_word_cs(&self, word: &str, replacement: &str) -> String {
let pattern = build_whole_word_pattern(word);
self.pattern_replace(&pattern, replacement, false)
}
fn replace_words(&self, pairs: &[(&str, &str)], case_insensitive: bool) -> String {
let mut output = self.clone();
for pair in pairs {
let (word, replacement) = *pair;
let pattern = build_whole_word_pattern(word);
output = output.pattern_replace(&pattern, replacement, case_insensitive);
}
output
}
fn replace_words_ci(&self, pairs: &[(&str, &str)]) -> String {
self.replace_words(pairs, true)
}
fn replace_words_cs(&self, pairs: &[(&str, &str)]) -> String {
self.replace_words(pairs, false)
}
fn replace_word_sets(&self, tuples: &[(&str, &str, bool)]) -> String {
let mut output = self.clone();
for row in tuples {
let (word, replacement, case_insensitive) = *row;
let pattern = build_whole_word_pattern(word);
output = output.pattern_replace(&pattern, replacement, case_insensitive);
}
output
}
}