#[inline]
pub fn is_bidi_control(c: char) -> bool {
matches!(
c,
'\u{200E}' | '\u{200F}' | '\u{202A}'..='\u{202E}' | '\u{2066}'..='\u{2069}'
)
}
pub fn strip_bidi(s: &str) -> String {
if s.chars().any(is_bidi_control) {
s.chars().filter(|c| !is_bidi_control(*c)).collect()
} else {
s.to_owned()
}
}
pub fn strip_bidi_opt(s: Option<String>) -> Option<String> {
s.map(|s| {
if s.chars().any(is_bidi_control) {
s.chars().filter(|c| !is_bidi_control(*c)).collect()
} else {
s
}
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lrm_stripped() {
assert_eq!(strip_bidi("\u{200E}5"), "5");
}
#[test]
fn all_bidi_controls_stripped() {
let raw = "a\u{200E}b\u{200F}c\u{202A}d\u{202B}e\u{202C}f\u{202D}g\u{202E}h\
\u{2066}i\u{2067}j\u{2068}k\u{2069}l";
assert_eq!(strip_bidi(raw), "abcdefghijkl");
}
#[test]
fn unaffected_text_unchanged() {
let clean = "Hello, δΈη! π";
assert_eq!(strip_bidi(clean), clean);
}
#[test]
fn empty_string() {
assert_eq!(strip_bidi(""), "");
}
#[test]
fn non_bidi_format_chars_preserved() {
let s = "a\u{200C}b\u{200D}c";
assert_eq!(strip_bidi(s), s);
}
#[test]
fn opt_some_stripped() {
assert_eq!(
strip_bidi_opt(Some("\u{200E}5".to_owned())),
Some("5".to_owned())
);
}
#[test]
fn opt_none() {
assert_eq!(strip_bidi_opt(None), None);
}
#[test]
fn no_allocation_path_returns_equal() {
let s = "no bidi here";
assert_eq!(strip_bidi(s), s);
}
}