string_patterns/utils.rs
1use regex::{Regex, Error};
2use crate::enums::WordBounds;
3
4/// Build a regular expression with an optional case-insenistive non-capturing group
5/// If the source pattern starts with a non-capturing group, this will be ignored irrespective of the case_insenistive flag
6pub fn build_regex(pattern: &str, case_insensitive: bool) -> Result<Regex, Error> {
7 let mut parts: Vec<&str> = vec![];
8 // do not case-insensitive flag if a similar flag is already in the regular expression
9 if case_insensitive && pattern.starts_with("(?") == false {
10 parts.push("(?i)");
11 }
12 parts.push(pattern);
13 let regex_str = parts. concat();
14 Regex::new(®ex_str)
15}
16
17// internal utility methods
18
19/// build regex pattern with word boundaries and WordBounds options
20pub(crate) fn build_word_pattern(word: &str, bounds: WordBounds) -> String {
21 bounds.to_pattern(word)
22}
23
24/// build regex pattern with whole word matches only. Does allow multiple word matches
25/// if wildcards allowing spaces or punctuation are in the regex patterm
26pub(crate) fn build_whole_word_pattern(word: &str) -> String {
27 build_word_pattern(word, WordBounds::Both)
28}
29
30/// constructs an optional match group for whole words from an array of strs
31/// e.g. &["cat?", "dog"] will match strings where cat and/or dog appear as whole words.
32/// should be used with build_regex above or pattern_match / pattern_replace
33pub(crate) fn build_optional_whole_word_pattern(words: &[&str]) -> String {
34 let word_pattern = ["(", &words.join("|"), ")"].concat();
35 build_word_pattern(&word_pattern, WordBounds::Both)
36}
37
38/*
39* Convert an str array to vector of tuple pairs with the second element having the same boolean value
40* as used in many multple match methods where the boolean element indicates case-sensitivity
41*/
42pub(crate) fn strs_to_str_bool_pairs<'a>(strs: &'a [&str], bool_val: bool) -> Vec<(&'a str, bool)> {
43 strs.into_iter().map(|s| (*s, bool_val)).collect()
44}