pub fn escape(s: &str) -> String {
escape_impl(s, false, false)
}
pub fn escape_special_only(s: &str) -> String {
escape_impl(s, true, false)
}
pub fn escape_literal_spaces(s: &str) -> String {
escape_impl(s, true, true)
}
fn escape_impl(s: &str, special_only: bool, literal_spaces: bool) -> String {
let mut out = String::with_capacity(s.len() * 2);
for c in s.chars() {
let is_special = matches!(
c,
'.' | '^' | '$' | '*' | '+' | '?' | '(' | ')' | '[' | ']' | '{' | '}' | '\\' | '|'
);
let is_space = c == ' ';
let is_punct = matches!(
c,
'!' | '"'
| '#'
| '%'
| '&'
| '\''
| ','
| ':'
| ';'
| '<'
| '='
| '>'
| '@'
| '`'
| '~'
| '/'
);
let escape_this =
is_special || (is_space && !literal_spaces) || (is_punct && !special_only);
if escape_this {
out.push('\\');
}
out.push(c);
}
out
}