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 &str/String
113impl PatternMatchMany for str {
114}
115
116
117/// Implement PatternMatchMany for vectors of strings.
118impl PatternMatchMany for [&str] {  
119}
120
121/// Test multiple false or positive patterns and return vector of booleans with the results for each item
122pub trait PatternMatchesMany where Self:PatternMatch {
123  fn pattern_matches_conditional(&self, pattern_sets: &[(&str, bool)], bounds:WordBounds) -> Vec<bool>;
124
125  fn pattern_word_matches_conditional(&self, pattern_sets: &[(&str, bool)]) -> Vec<bool> {
126    self.pattern_matches_conditional(&pattern_sets, WordBounds::Both)
127  }
128
129  fn pattern_matches_conditional_ci(&self, patterns: &[&str]) -> Vec<bool> {
130    let pattern_sets: Vec<(&str, bool)> = strs_to_str_bool_pairs(patterns, true);
131    self.pattern_matches_conditional(&pattern_sets, WordBounds::None)
132  }
133
134  fn pattern_matches_conditional_cs(&self, patterns: &[&str]) -> Vec<bool> {
135    let pattern_sets: Vec<(&str, bool)> = strs_to_str_bool_pairs(patterns, false);
136    self.pattern_matches_conditional(&pattern_sets, WordBounds::None)
137  }
138
139  fn pattern_word_matches_conditional_ci(&self, patterns: &[&str]) -> Vec<bool> {
140    let pattern_sets: Vec<(&str, bool)> = strs_to_str_bool_pairs(patterns, true);
141    self.pattern_matches_conditional(&pattern_sets, WordBounds::Both)
142  }
143
144  fn pattern_word_matches_conditional_cs(&self, patterns: &[&str]) -> Vec<bool> {
145    let pattern_sets: Vec<(&str, bool)> = strs_to_str_bool_pairs(patterns, false);
146    self.pattern_matches_conditional(&pattern_sets, WordBounds::Both)
147  }
148}
149
150impl PatternMatchesMany for str {
151  /// test for multiple conditions. All other trait methods are derived from this
152  fn pattern_matches_conditional(&self, pattern_sets: &[(&str, bool)], bounds:WordBounds) -> Vec<bool> {
153    let mut matched_items: Vec<bool> = Vec::with_capacity(pattern_sets.len());
154    for pattern_set in pattern_sets {
155       let (pattern, case_insensitive) = *pattern_set;
156       let bounded_pat = bounds.to_pattern(pattern);
157       let is_matched = self.pattern_match(&bounded_pat, case_insensitive);
158       matched_items.push(is_matched);
159     }
160     matched_items
161   }
162}
163
164/// Provides methods to replace with multiple patterns 
165/// expressed as arrays of tuples
166pub trait PatternReplaceMany {
167  /// Replaces multiple sets of patterns with replacements in case-sensitive mode
168  /// with an array of tuples (pattern, replacement, case_insensitive)
169  fn pattern_replace_pairs(&self, replacement_sets: &[(&str, &str)], case_insensitive: bool) -> Self where Self: Sized;
170
171  /// Replaces multiple sets of patterns with replacements in case-insensitive mode
172  /// with an array of tuples (pattern, replacement, case_insensitive)
173  fn pattern_replace_pairs_ci(&self, replacement_sets: &[(&str, &str)]) -> Self where Self: Sized {
174    self.pattern_replace_pairs(replacement_sets, true)
175  }
176
177  /// Replaces multiple sets of patterns with replacements in case-insensitive mode
178  /// with an array of tuples (pattern, replacement, case_insensitive)
179  fn pattern_replace_pairs_cs(&self, replacement_sets: &[(&str, &str)]) -> Self where Self: Sized {
180    self.pattern_replace_pairs(replacement_sets, false)
181  }
182
183  /// Replaces multiple sets of patterns with replacements in case-sensitive mode
184  /// with an array of simple tuples (pattern, replacement)
185  fn pattern_replace_sets(&self, replacement_sets: &[(&str, &str, bool)]) -> Self where Self: Sized;
186}
187
188impl PatternReplaceMany for String {
189  /// Replaces multiple sets of patterns with replacements and boolean case sensitivity 
190  /// with an array of tuples (pattern, replacement, case_insensitive)
191  fn pattern_replace_sets(&self, replacement_sets: &[(&str, &str, bool)]) -> String {
192    let mut return_string = self.clone();
193    for replacement_set in replacement_sets {
194      let (pattern, replacement, case_insensitive) = *replacement_set;
195      if let Ok(new_string) = return_string.pattern_replace_result(pattern, replacement, case_insensitive) {
196        return_string = new_string;
197      }
198    }
199    return_string
200  }
201
202  /// Replaces multiple sets of patterns with replacements in case-sensitive mode
203  /// with an array of simple tuples (pattern, replacement)
204  fn pattern_replace_pairs(&self, replacement_pairs: &[(&str, &str)], case_sensitive: bool) -> String {
205    let mut return_string = self.clone();
206    for replacement_pair in replacement_pairs {
207      let (pattern, replacement) = *replacement_pair;
208      if let Ok(new_string) = return_string.pattern_replace_result(pattern, replacement, case_sensitive) {
209        return_string = new_string;
210      }
211    }
212    return_string
213  }
214}
215
216
217/// ReplaceMany implementation for vectors of owned strings
218impl PatternReplaceMany for Vec<String> {
219
220  /// Replace all matched patterns with mixed case-sensitivity flags, expressed as tuples of (pattern: &str, replacement: &str, case_insensitive: bool)
221  fn pattern_replace_sets(&self, replacement_sets: &[(&str, &str, bool)]) -> Vec<String> {
222    let mut return_strings = self.clone();
223    for replacement_set in replacement_sets {
224      let (pattern, replacement, case_insensitive) = *replacement_set;
225      if let Ok(new_strings) = return_strings.pattern_replace_result(pattern, replacement, case_insensitive) {
226        return_strings = new_strings;
227      }
228    }
229    return_strings
230  }
231
232  /// Replace all matched patterns in case-sensitive mode (unless defined in the pattern via (?i)),
233  /// expressed as tuples of (pattern: &str, replacement: &str)
234  fn pattern_replace_pairs(&self, replacement_pairs: &[(&str, &str)], case_insensitive: bool) -> Vec<String> {
235    let mut return_strings = self.clone();
236    for replacement_pair in replacement_pairs {
237      let (pattern, replacement) = *replacement_pair;
238      if let Ok(new_string) = return_strings.pattern_replace_result(pattern, replacement, case_insensitive) {
239        return_strings = new_string;
240      }
241    }
242    return_strings
243  }
244}