kutil_std/string/
escape.rs

1/// Escape character.
2pub const ESCAPE_CHARACTER: char = '\\';
3
4//
5// Escape
6//
7
8/// Escape utilities.
9pub trait Escape {
10    /// Replaces escaped patterns with the pattern.
11    fn unescape(&self, pattern: &str) -> String;
12
13    /// Find while ignoring escaped patterns.
14    fn find_ignore_escaped(&self, pattern: &str) -> Option<usize>;
15
16    /// Split once while ignoring escaped patterns.
17    fn split_once_ignore_escaped(&self, pattern: &str) -> Option<(&str, &str)>;
18}
19
20impl Escape for str {
21    fn unescape(&self, pattern: &str) -> String {
22        let escaped_pattern = String::from(ESCAPE_CHARACTER) + pattern;
23        self.replace(&escaped_pattern, pattern)
24    }
25
26    fn find_ignore_escaped(&self, pattern: &str) -> Option<usize> {
27        let pattern_chars: Vec<_> = pattern.chars().collect();
28        let pattern_chars_count = pattern_chars.len();
29
30        let mut escaped = false;
31        let mut pattern_chars_index = 0;
32
33        for (byte_index, c) in self.char_indices() {
34            if c == pattern_chars[pattern_chars_index] {
35                pattern_chars_index += 1;
36                if pattern_chars_index == pattern_chars_count {
37                    if escaped {
38                        pattern_chars_index = 0;
39                        escaped = false;
40                    } else {
41                        return Some(byte_index - pattern.len() + 1);
42                    }
43                }
44            } else if c == ESCAPE_CHARACTER {
45                escaped = true;
46            } else {
47                escaped = false;
48            }
49        }
50
51        None
52    }
53
54    fn split_once_ignore_escaped(&self, pattern: &str) -> Option<(&str, &str)> {
55        self.find_ignore_escaped(pattern).map(|index| (&self[..index], &self[index + pattern.len()..]))
56    }
57}