pub trait ContainsAndSkipBrackets { fn contains_and_skip_brackets(&self, pattern: &str) -> bool; } impl ContainsAndSkipBrackets for String { fn contains_and_skip_brackets(&self, pattern: &str) -> bool { if self.contains(pattern) { let (first, _) = self.split_once(pattern).unwrap(); let opening_count = first.chars().filter(|c| *c == '(').count(); let closing_count = first.chars().filter(|c| *c == ')').count(); return opening_count == closing_count; } false } } pub trait SplitMatchingBracket { fn split_on_matching_bracket(&self) -> (&str, &str); fn split_once_and_skipt_brackets(&self, pattern: char) -> Option<(&str, &str)>; } impl SplitMatchingBracket for String { fn split_on_matching_bracket(&self) -> (&str, &str) { let mut i = 0; let mut bracket_balance = -1; for c in self.chars() { i += 1; match c { '(' => bracket_balance += 1, ')' => bracket_balance -= 1, _ => {} } if bracket_balance < 0 { break; } } self.split_at(i) } fn split_once_and_skipt_brackets(&self, pattern: char) -> Option<(&str, &str)> { let mut i = 0; let mut bracket_balance = 0; for c in self.chars() { i += 1; match c { '(' => bracket_balance += 1, ')' => bracket_balance -= 1, _ => {} } if bracket_balance <= 0 && c == pattern { let (a, b) = self.split_at(i); return Some((&a[0..a.len() - 1], b)) } } None } }