1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
use regex::{Match,Captures};
use crate::utils::{build_regex, build_whole_word_pattern};
/// Set of methods to capture groups or match objects derived from Regex::captures.
pub trait PatternCapture {
/// Yields an option with Regex::Captures as returned from re.captures, Accepts a boolean case_insensitive flag
fn pattern_captures(&self, pattern: &str, case_insensitive: bool) -> Option<Captures>;
/// Yields a vector of Match objects with start and end index + the captured string. Accepts a boolean case_insensitive flag
fn pattern_matches_vec(&self, pattern: &str, case_insensitive: bool) -> Vec<Match>;
/// Yields an option with first match object if available with a boolean case_insensitive flag
fn pattern_first_match(&self, pattern: &str, case_insensitive: bool) -> Option<Match>;
/// Yields an option with last match object if available with a boolean case_insensitive flag
fn pattern_last_match(&self, pattern: &str, case_insensitive: bool) -> Option<Match>;
/// returns an option with a pair of match objects
/// If there is only one match the match objects will have the same indices
fn pattern_first_last_matches(&self, pattern: &str, case_insensitive: bool) -> Option<(Match, Match)>;
/// Yields an option with an unsigned integer for the index of the start of the first match
/// with a boolean case_insensitive flag
fn pattern_first_index(&self, pattern: &str, case_insensitive: bool) -> Option<usize>;
/// Yields an option with an unsigned integer for the index of the end of the first match
/// with a boolean case_insensitive flag
fn pattern_first_end_index(&self, pattern: &str, case_insensitive: bool) -> Option<usize>;
/// Yields an option with an unsigned integer for the index of the start of the last match
/// with a boolean case_insensitive flag
fn pattern_last_start_index(&self, pattern: &str, case_insensitive: bool) -> Option<usize>;
/// Yields an option with an unsigned integer for the index of the end of the last match
/// with a boolean case_insensitive flag
fn pattern_last_index(&self, pattern: &str, case_insensitive: bool) -> Option<usize>;
// Counts the number of matches with a boolean case_insensitive flag
fn count_pattern(&self, pattern: &str, case_insensitive: bool) -> usize;
// Counts the number of whole words with a boolean case_insensitive flag
fn count_word(&self, word: &str, case_insensitive: bool) -> usize;
}
impl PatternCapture for str {
// Yields an option with Regex::Captures as returned from re.captures, Accepts a boolean case_insensitive flag
fn pattern_captures(&self, pattern: &str, case_insensitive: bool) -> Option<Captures> {
if let Ok(re) = build_regex(pattern, case_insensitive) {
re.captures(self)
} else {
None
}
}
/// Yields a vector of Match objects with start and end index + the captured string. Accepts a boolean case_insensitive flag
fn pattern_matches_vec(&self, pattern: &str, case_insensitive: bool) -> Vec<Match> {
if let Ok(re) = build_regex(pattern, case_insensitive) {
let mut matched_items: Vec<Match> = Vec::new();
for capture in re.captures_iter(self) {
for matched_opt in capture.iter() {
if let Some(matched_item) = matched_opt {
matched_items.push(matched_item);
}
}
}
matched_items
} else {
vec![]
}
}
/// Yields an option with first match object if available with a boolean case_insensitive flag
/// As this uses re.find it will be fast than the matching last_match method
fn pattern_first_match(&self, pattern: &str, case_insensitive: bool) -> Option<Match> {
if let Ok(re) = build_regex(pattern, case_insensitive) {
re.find(self)
} else {
None
}
}
/// Yields an option with last match object if available with a boolean case_insensitive flag
fn pattern_last_match(&self, pattern: &str, case_insensitive: bool) -> Option<Match> {
let matched_segments = self.pattern_matches_vec(pattern, case_insensitive);
if let Some(last) = matched_segments.last() {
Some(*last)
} else {
None
}
}
/// returns an option with a pair of match objects
/// If there is only one match the match objects will have the same indices
fn pattern_first_last_matches(&self, pattern: &str, case_insensitive: bool) -> Option<(Match, Match)> {
let matched_segments = self.pattern_matches_vec(pattern, case_insensitive);
if let Some(first) = matched_segments.get(0) {
if let Some(last) = matched_segments.last() {
return Some((*first, *last));
}
}
None
}
/// Yields an option with an unsigned integer for the index of the start of the last match
/// with a boolean case_insensitive flag
fn pattern_first_index(&self, pattern: &str, case_insensitive: bool) -> Option<usize> {
if let Some(first) = self.pattern_first_match(pattern, case_insensitive) {
Some(first.start())
} else {
None
}
}
/// Yields an option with an unsigned integer for the index of the end of the first match
/// with a boolean case_insensitive flag
fn pattern_first_end_index(&self, pattern: &str, case_insensitive: bool) -> Option<usize> {
if let Some(first) = self.pattern_first_match(pattern, case_insensitive) {
Some(first.end())
} else {
None
}
}
/// Yields an option with an unsigned integer for the index of the start of the last match
/// with a boolean case_insensitive flag
fn pattern_last_start_index(&self, pattern: &str, case_insensitive: bool) -> Option<usize> {
if let Some(first) = self.pattern_first_match(pattern, case_insensitive) {
Some(first.start())
} else {
None
}
}
// Yields an option with an unsigned integer for the index of the end of the last match
/// with a boolean case_insensitive flag
fn pattern_last_index(&self, pattern: &str, case_insensitive: bool) -> Option<usize> {
if let Some(first) = self.pattern_first_match(pattern, case_insensitive) {
Some(first.end())
} else {
None
}
}
// Counts the number of matches with a boolean case_insensitive flag
fn count_pattern(&self, pattern: &str, case_insensitive: bool) -> usize {
self.pattern_matches_vec(pattern, case_insensitive).len()
}
// Counts the number of matches with a boolean case_insensitive flag
fn count_word(&self, word: &str, case_insensitive: bool) -> usize {
let pattern = build_whole_word_pattern(word);
self.pattern_matches_vec(&pattern, case_insensitive).len()
}
}