pub const ESCAPE_CHARACTER: char = '\\';
pub trait Escape {
fn unescape(&self, pattern: &str) -> String;
fn find_ignore_escaped(&self, pattern: &str) -> Option<usize>;
fn split_once_ignore_escaped(&self, pattern: &str) -> Option<(&str, &str)>;
}
impl Escape for str {
fn unescape(&self, pattern: &str) -> String {
let escaped_pattern = String::from(ESCAPE_CHARACTER) + pattern;
self.replace(&escaped_pattern, pattern)
}
fn find_ignore_escaped(&self, pattern: &str) -> Option<usize> {
let pattern_chars: Vec<_> = pattern.chars().collect();
let pattern_chars_count = pattern_chars.len();
let mut escaped = false;
let mut pattern_chars_index = 0;
for (byte_index, c) in self.char_indices() {
if c == pattern_chars[pattern_chars_index] {
pattern_chars_index += 1;
if pattern_chars_index == pattern_chars_count {
if escaped {
pattern_chars_index = 0;
escaped = false;
} else {
return Some(byte_index - pattern.len() + 1);
}
}
} else if c == ESCAPE_CHARACTER {
escaped = true;
} else {
escaped = false;
}
}
None
}
fn split_once_ignore_escaped(&self, pattern: &str) -> Option<(&str, &str)> {
self.find_ignore_escaped(pattern).map(|index| (&self[..index], &self[index + pattern.len()..]))
}
}