#[inline]
pub fn is_digit(c: char, ascii: bool) -> bool {
if ascii {
c.is_ascii_digit()
} else {
c.is_numeric()
}
}
#[inline]
pub fn is_word(c: char, ascii: bool) -> bool {
if ascii {
c.is_ascii_alphanumeric() || c == '_'
} else {
c.is_alphanumeric() || c == '_'
}
}
#[inline]
pub fn is_space(c: char, ascii: bool) -> bool {
if ascii {
matches!(c, ' ' | '\t' | '\n' | '\x0b' | '\x0c' | '\r')
} else {
c.is_whitespace()
}
}
#[inline]
pub fn case_eq(a: char, b: char) -> bool {
if a == b {
return true;
}
let la = a.to_lowercase();
let lb = b.to_lowercase();
la.eq(lb)
}
pub fn push_case_variants(c: char, out: &mut Vec<char>) {
out.push(c);
for u in c.to_uppercase() {
if u != c {
out.push(u);
}
}
for l in c.to_lowercase() {
if l != c {
out.push(l);
}
}
}
pub type PropFn = fn(char) -> bool;
pub fn property(name: &str) -> Option<PropFn> {
let key: String = name
.chars()
.filter(|c| !matches!(c, ' ' | '_' | '-'))
.flat_map(|c| c.to_lowercase())
.collect();
let (prop, value) = match key.split_once('=') {
Some((p, v)) => (p, v),
None => ("", key.as_str()),
};
let pred: PropFn = match (prop, value) {
("", "l") | ("gc", "l") | ("", "letter") => |c| c.is_alphabetic(),
("", "lu") | ("gc", "lu") | ("", "uppercaseletter") => |c| c.is_uppercase(),
("", "ll") | ("gc", "ll") | ("", "lowercaseletter") => |c| c.is_lowercase(),
("", "n") | ("gc", "n") | ("", "number") => |c| c.is_numeric(),
("", "nd") | ("gc", "nd") | ("generalcategory", "nd") | ("", "decimalnumber") => {
|c| c.is_numeric()
}
("", "nl") | ("gc", "nl") | ("", "letternumber") => |c| c.is_numeric(),
("", "no") | ("gc", "no") | ("", "othernumber") => |c| c.is_numeric(),
("", "p") | ("gc", "p") | ("", "punctuation") => |c| {
matches!(
c,
'?' | '!'
| '.'
| ','
| ';'
| ':'
| '-'
| '—'
| '('
| ')'
| '['
| ']'
| '{'
| '}'
| '"'
| '\''
| '`'
| '/'
| '\\'
| '…'
| '‥'
)
},
("", "z") | ("gc", "z") | ("", "separator") => {
|c| matches!(c, ' ' | '\u{00a0}' | '\u{2028}' | '\u{2029}')
}
("", "c") | ("gc", "c") | ("", "other") => |c| !c.is_alphanumeric() && !c.is_whitespace(),
("", "alpha" | "alphabetic") => |c| c.is_alphabetic(),
("", "alnum" | "alphanumeric") => |c| c.is_alphanumeric(),
("", "upper" | "uppercase") => |c| c.is_uppercase(),
("", "lower" | "lowercase") => |c| c.is_lowercase(),
("", "space" | "whitespace") => |c| c.is_whitespace(),
("", "digit") => |c| c.is_numeric(),
("", "ascii") => |c| c.is_ascii(),
("", "blank") => |c| matches!(c, ' ' | '\t'),
("", "cntrl" | "control") => |c| c.is_control(),
("", "print" | "printable") => |c| !c.is_control(),
("", "graph") => |c| c.is_alphanumeric() || c.is_ascii_punctuation(),
("", "word") => |c| c.is_alphanumeric() || c == '_',
("", "xdigit" | "hexdigit") => |c| c.is_ascii_hexdigit(),
("", "posixalnum") => |c| c.is_alphanumeric(),
("", "posixdigit") => |c| c.is_numeric(),
("", "posixpunct") => |c| {
c.is_ascii_punctuation()
|| "\u{2010}\u{2011}\u{2012}\u{2013}\u{2014}\u{2015}\u{2212}".contains(c)
},
("", "posixxdigit") => |c| c.is_ascii_hexdigit(),
_ => return None,
};
Some(pred)
}