Skip to main content

string_patterns/
pattern_many.rs

1use crate::{utils::strs_to_str_bool_pairs, PatternMatch, PatternReplace, WordBounds};
2
3/// Provides methods to match with multiple patterns 
4/// expressed as arrays of tuples or simple strs (for pattern_match_all_ci and pattern_match_all_cs)
5pub trait PatternMatchMany where Self:PatternMatch {
6  /// Matches all of the patterns in case-sensitivity flag
7  /// with an array of tuples (patterns, case_insensitive)
8  fn pattern_match_all(&self, patterns: &[&str], case_insensitive: bool) -> bool {
9    let mut num_matched:usize = 0;
10    let num_patterns = patterns.len();
11    for pattern in patterns {
12      if self.pattern_match(pattern, case_insensitive) {
13        num_matched += 1;
14      }
15    }
16    num_matched == num_patterns
17  }
18
19  /// Matches all of the patterns with case-insensitive flag
20  /// e.g. ```(r#"a[ck]"#, true)``` "ac" or "ak" whether upper, lower or mixed case
21  /// with an array of tuples (pattern, replacement, case_insensitive)
22  /// Consider renaming with _all_
23  fn pattern_match_all_mixed(&self, pattern_sets: &[(&str, bool)]) -> bool {
24    let mut num_matched:usize = 0;
25    let num_patterns = pattern_sets.len();
26    for pair in pattern_sets {
27      let (pattern, case_insensitive) = *pair;
28      if self.pattern_match(pattern, case_insensitive) {
29        num_matched += 1;
30      }
31    }
32    num_matched == num_patterns
33  }
34
35  /// Matches all of the patterns with positivity condition and case-insensitive flag
36  /// e.g. ```(false, "a[ck]", true)``` does not contain "ac" or "ak" whether upper, lower or mixed case
37  /// with an array of tuples (positive, pattern, case_insensitive)
38  fn pattern_match_all_conditional(&self, pattern_sets: &[(bool, &str, bool)]) -> bool {
39    let mut num_matched:usize = 0;
40    let num_patterns = pattern_sets.len();
41    for pattern_set in pattern_sets {
42      let (is_positive, pattern, case_insensitive) = *pattern_set;
43      let is_matched = self.pattern_match(pattern, case_insensitive);
44      if is_matched == is_positive {
45        num_matched += 1;
46      }
47    }
48    num_matched == num_patterns
49  }
50
51  /// Matches all of the patterns in case-insensitive mode
52  /// with an array of str patterns
53  fn pattern_match_all_ci(&self, patterns: &[&str]) -> bool {
54    self.pattern_match_all(patterns, true)
55  }
56
57  /// Matches all of the patterns in case-sensitive mode
58  /// with an array of str patterns 
59  fn pattern_match_all_cs(&self, patterns: &[&str]) -> bool {
60    self.pattern_match_all(patterns, false)
61  }
62  
63  /// Matches one or more of the patterns in case-sensitivity flag
64  /// with an array of tuples (patterns, case_insensitive)
65  fn pattern_match_any(&self, patterns: &[&str], case_insensitive: bool) -> bool {
66    for pattern in patterns {
67      if self.pattern_match(pattern, case_insensitive) {
68         return true;
69      }
70    }
71    false
72  }
73
74  /// Matches one or more of the patterns in case-insensitive mode
75  /// with an array of str patterns
76  fn pattern_match_any_ci(&self, patterns: &[&str]) -> bool {
77    self.pattern_match_any(patterns, true)
78  }
79
80  /// Matches one or more of the patterns in case-sensitive mode
81  /// with an array of str patterns
82  fn pattern_match_any_cs(&self, patterns: &[&str]) -> bool {
83    self.pattern_match_any(patterns, false)
84  }
85
86  /// Matches one or more of the patterns with case-insensitive flag
87  /// e.g. ```(r#"a[ck]"#, true)``` matches "ac" or "ak" whether upper, lower or mixed case
88  /// with an array of tuples (pattern, replacement, case_insensitive)
89  fn pattern_match_any_mixed(&self, pattern_sets: &[(&str, bool)]) -> bool {
90    for pair in pattern_sets {
91      let (pattern, case_insensitive) = *pair;
92      if self.pattern_match(pattern, case_insensitive) {
93         return true;
94      }
95    }
96    false
97  }
98
99  /// Matches one or more of the patterns with positivity condition and case-insensitive flag
100  fn pattern_match_any_conditional(&self, pattern_sets: &[(bool, &str, bool)]) -> bool {
101   for pattern_set in pattern_sets {
102      let (is_positive, pattern, case_insensitive) = *pattern_set;
103      let is_matched = self.pattern_match(pattern, case_insensitive);
104      if is_matched == is_positive {
105         return true;
106      }
107    }
108    false
109  }
110}
111
112/// Implement PatternMatchMany for any string-like type (&str, String, &String, `Cow<str>`, etc.)
113impl<T: AsRef<str>> PatternMatchMany for T {
114}
115
116/// Implement PatternMatchMany for arrays or vectors of any string-like type
117impl<T: AsRef<str>> PatternMatchMany for [T] {
118}
119
120/// Test multiple false or positive patterns and return vector of booleans with the results for each item
121pub trait PatternMatchesMany where Self:PatternMatch {
122  fn pattern_matches_conditional(&self, pattern_sets: &[(&str, bool)], bounds:WordBounds) -> Vec<bool>;
123
124  fn pattern_word_matches_conditional(&self, pattern_sets: &[(&str, bool)]) -> Vec<bool> {
125    self.pattern_matches_conditional(&pattern_sets, WordBounds::Both)
126  }
127
128  fn pattern_matches_conditional_ci(&self, patterns: &[&str]) -> Vec<bool> {
129    let pattern_sets: Vec<(&str, bool)> = strs_to_str_bool_pairs(patterns, true);
130    self.pattern_matches_conditional(&pattern_sets, WordBounds::None)
131  }
132
133  fn pattern_matches_conditional_cs(&self, patterns: &[&str]) -> Vec<bool> {
134    let pattern_sets: Vec<(&str, bool)> = strs_to_str_bool_pairs(patterns, false);
135    self.pattern_matches_conditional(&pattern_sets, WordBounds::None)
136  }
137
138  fn pattern_word_matches_conditional_ci(&self, patterns: &[&str]) -> Vec<bool> {
139    let pattern_sets: Vec<(&str, bool)> = strs_to_str_bool_pairs(patterns, true);
140    self.pattern_matches_conditional(&pattern_sets, WordBounds::Both)
141  }
142
143  fn pattern_word_matches_conditional_cs(&self, patterns: &[&str]) -> Vec<bool> {
144    let pattern_sets: Vec<(&str, bool)> = strs_to_str_bool_pairs(patterns, false);
145    self.pattern_matches_conditional(&pattern_sets, WordBounds::Both)
146  }
147}
148
149impl<T: AsRef<str>> PatternMatchesMany for T {
150  /// test for multiple conditions. All other trait methods are derived from this
151  fn pattern_matches_conditional(&self, pattern_sets: &[(&str, bool)], bounds:WordBounds) -> Vec<bool> {
152    let mut matched_items: Vec<bool> = Vec::with_capacity(pattern_sets.len());
153    for pattern_set in pattern_sets {
154       let (pattern, case_insensitive) = *pattern_set;
155       let bounded_pat = bounds.to_pattern(pattern);
156       let is_matched = self.pattern_match(&bounded_pat, case_insensitive);
157       matched_items.push(is_matched);
158     }
159     matched_items
160   }
161}
162
163/// Provides methods to replace with multiple patterns 
164/// expressed as arrays of tuples
165pub trait PatternReplaceMany {
166  /// Replaces multiple sets of patterns with replacements in case-sensitive mode
167  /// with an array of tuples (pattern, replacement, case_insensitive)
168  fn pattern_replace_pairs(&self, replacement_sets: &[(&str, &str)], case_insensitive: bool) -> Self where Self: Sized;
169
170  /// Replaces multiple sets of patterns with replacements in case-insensitive mode
171  /// with an array of tuples (pattern, replacement, case_insensitive)
172  fn pattern_replace_pairs_ci(&self, replacement_sets: &[(&str, &str)]) -> Self where Self: Sized {
173    self.pattern_replace_pairs(replacement_sets, true)
174  }
175
176  /// Replaces multiple sets of patterns with replacements in case-insensitive mode
177  /// with an array of tuples (pattern, replacement, case_insensitive)
178  fn pattern_replace_pairs_cs(&self, replacement_sets: &[(&str, &str)]) -> Self where Self: Sized {
179    self.pattern_replace_pairs(replacement_sets, false)
180  }
181
182  /// Replaces multiple sets of patterns with replacements in case-sensitive mode
183  /// with an array of simple tuples (pattern, replacement)
184  fn pattern_replace_sets(&self, replacement_sets: &[(&str, &str, bool)]) -> Self where Self: Sized;
185}
186
187impl PatternReplaceMany for String {
188  /// Replaces multiple sets of patterns with replacements and boolean case sensitivity 
189  /// with an array of tuples (pattern, replacement, case_insensitive)
190  fn pattern_replace_sets(&self, replacement_sets: &[(&str, &str, bool)]) -> String {
191    let mut return_string = self.clone();
192    for replacement_set in replacement_sets {
193      let (pattern, replacement, case_insensitive) = *replacement_set;
194      if let Ok(new_string) = return_string.pattern_replace_result(pattern, replacement, case_insensitive) {
195        return_string = new_string;
196      }
197    }
198    return_string
199  }
200
201  /// Replaces multiple sets of patterns with replacements in case-sensitive mode
202  /// with an array of simple tuples (pattern, replacement)
203  fn pattern_replace_pairs(&self, replacement_pairs: &[(&str, &str)], case_sensitive: bool) -> String {
204    let mut return_string = self.clone();
205    for replacement_pair in replacement_pairs {
206      let (pattern, replacement) = *replacement_pair;
207      if let Ok(new_string) = return_string.pattern_replace_result(pattern, replacement, case_sensitive) {
208        return_string = new_string;
209      }
210    }
211    return_string
212  }
213}
214
215
216/// ReplaceMany implementation for vectors of owned strings
217impl PatternReplaceMany for Vec<String> {
218
219  /// Replace all matched patterns with mixed case-sensitivity flags, expressed as tuples of (pattern: &str, replacement: &str, case_insensitive: bool)
220  fn pattern_replace_sets(&self, replacement_sets: &[(&str, &str, bool)]) -> Vec<String> {
221    let mut return_strings = self.clone();
222    for replacement_set in replacement_sets {
223      let (pattern, replacement, case_insensitive) = *replacement_set;
224      if let Ok(new_strings) = return_strings.pattern_replace_result(pattern, replacement, case_insensitive) {
225        return_strings = new_strings;
226      }
227    }
228    return_strings
229  }
230
231  /// Replace all matched patterns in case-sensitive mode (unless defined in the pattern via (?i)),
232  /// expressed as tuples of (pattern: &str, replacement: &str)
233  fn pattern_replace_pairs(&self, replacement_pairs: &[(&str, &str)], case_insensitive: bool) -> Vec<String> {
234    let mut return_strings = self.clone();
235    for replacement_pair in replacement_pairs {
236      let (pattern, replacement) = *replacement_pair;
237      if let Ok(new_string) = return_strings.pattern_replace_result(pattern, replacement, case_insensitive) {
238        return_strings = new_string;
239      }
240    }
241    return_strings
242  }
243}