pub fn clean(input: &str) -> String {
let mut out = String::with_capacity(input.len());
for ch in input.chars() {
match ch {
'\t' => out.push(' '),
c if (c as u32) < 0x20 || c as u32 == 0x7f => {}
c if (0x80..=0x9f).contains(&(c as u32)) => {}
'\u{200b}'
| '\u{200e}'
| '\u{200f}'
| '\u{202a}'..='\u{202e}'
| '\u{2066}'..='\u{2069}'
| '\u{feff}' => {}
c => out.push(c),
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn strips_escape_sequences() {
let evil = "hi\u{1b}]0;pwned\u{7}\u{1b}[31mred\u{1b}[0m";
assert_eq!(clean(evil), "hi]0;pwned[31mred[0m");
assert!(!clean(evil).contains('\u{1b}'));
assert!(!clean(evil).contains('\u{7}'));
}
#[test]
fn keeps_text_and_emoji() {
assert_eq!(clean("gigachad 🔥 KEKW"), "gigachad 🔥 KEKW");
}
#[test]
fn drops_bidi_and_zero_width() {
assert_eq!(clean("a\u{202e}b\u{200b}c"), "abc");
}
#[test]
fn tab_becomes_space_newline_dropped() {
assert_eq!(clean("a\tb\nc"), "a bc");
}
}