static COMPATIBILITY_EXPANSIONS: &[(u32, &str)] = &[
(0x2100, "a/c"),
(0x2101, "a/s"),
(0x2105, "c/o"),
(0x2106, "c/u"),
(0x2107, "Ɛ"),
(0x210F, "ħ"),
(0x2113, "l"),
(0x2120, "SM"),
(0x2121, "TEL"),
(0x212B, "Å"),
(0x213B, "FAX"),
(0x2145, "D"),
(0x2146, "d"),
(0x2147, "e"),
(0x2148, "i"),
(0x2149, "j"),
(0x3250, "PTE"),
(0x3251, "21"),
(0x3252, "22"),
(0x3253, "23"),
(0x3254, "24"),
(0x3255, "25"),
(0x3256, "26"),
(0x3257, "27"),
(0x3258, "28"),
(0x3259, "29"),
(0x325A, "30"),
(0x325B, "31"),
(0x325C, "32"),
(0x325D, "33"),
(0x325E, "34"),
(0x325F, "35"),
(0x32B1, "36"),
(0x32B2, "37"),
(0x32B3, "38"),
(0x32B4, "39"),
(0x32B5, "40"),
(0x32B6, "41"),
(0x32B7, "42"),
(0x32B8, "43"),
(0x32B9, "44"),
(0x32BA, "45"),
(0x32BB, "46"),
(0x32BC, "47"),
(0x32BD, "48"),
(0x32BE, "49"),
(0x32BF, "50"),
(0x32CC, "Hg"),
(0x32CD, "erg"),
(0x32CE, "eV"),
(0x32CF, "LTD"),
(0x3371, "hPa"),
(0x3372, "da"),
(0x3373, "AU"),
(0x3374, "bar"),
(0x3375, "oV"),
(0x3376, "pc"),
(0x3377, "dm"),
(0x3378, "dm2"),
(0x3379, "dm3"),
(0x337A, "IU"),
(0x3380, "pA"),
(0x3381, "nA"),
(0x3383, "mA"),
(0x3384, "kA"),
(0x3385, "KB"),
(0x3386, "MB"),
(0x3387, "GB"),
(0x3388, "cal"),
(0x3389, "kcal"),
(0x338A, "pF"),
(0x338B, "nF"),
(0x338E, "mg"),
(0x338F, "kg"),
(0x3390, "Hz"),
(0x3391, "kHz"),
(0x3392, "MHz"),
(0x3393, "GHz"),
(0x3394, "THz"),
(0x3396, "ml"),
(0x3397, "dl"),
(0x3398, "kl"),
(0x3399, "fm"),
(0x339A, "nm"),
(0x339C, "mm"),
(0x339D, "cm"),
(0x339E, "km"),
(0x339F, "mm2"),
(0x33A0, "cm2"),
(0x33A1, "m2"),
(0x33A2, "km2"),
(0x33A3, "mm3"),
(0x33A4, "cm3"),
(0x33A5, "m3"),
(0x33A6, "km3"),
(0x33A9, "Pa"),
(0x33AA, "kPa"),
(0x33AB, "MPa"),
(0x33AC, "GPa"),
(0x33AD, "rad"),
(0x33B0, "ps"),
(0x33B1, "ns"),
(0x33B3, "ms"),
(0x33B4, "pV"),
(0x33B5, "nV"),
(0x33B7, "mV"),
(0x33B8, "kV"),
(0x33B9, "MV"),
(0x33BA, "pW"),
(0x33BB, "nW"),
(0x33BD, "mW"),
(0x33BE, "kW"),
(0x33BF, "MW"),
(0x33C2, "a.m."),
(0x33C3, "Bq"),
(0x33C4, "cc"),
(0x33C5, "cd"),
(0x33C7, "Co."),
(0x33C8, "dB"),
(0x33C9, "Gy"),
(0x33CA, "ha"),
(0x33CB, "HP"),
(0x33CC, "in"),
(0x33CD, "KK"),
(0x33CE, "KM"),
(0x33CF, "kt"),
(0x33D0, "lm"),
(0x33D1, "ln"),
(0x33D2, "log"),
(0x33D3, "lx"),
(0x33D4, "mb"),
(0x33D5, "mil"),
(0x33D6, "mol"),
(0x33D7, "PH"),
(0x33D8, "p.m."),
(0x33D9, "PPM"),
(0x33DA, "PR"),
(0x33DB, "sr"),
(0x33DC, "Sv"),
(0x33DD, "Wb"),
(0x33FF, "gal"),
(0xFB03, "ffi"),
(0xFB04, "ffl"),
(0xFB29, "+"),
(0xFE30, ".."),
(0xFE33, "_"),
(0xFE34, "_"),
(0xFE35, "("),
(0xFE36, ")"),
(0xFE37, "{"),
(0xFE38, "}"),
(0xFE47, "["),
(0xFE48, "]"),
(0xFE4D, "_"),
(0xFE4E, "_"),
(0xFE4F, "_"),
(0xFF01, "!"),
(0xFF02, "\""),
(0xFF07, "'"),
(0xFF08, "("),
(0xFF09, ")"),
(0xFF0C, ","),
(0xFF0D, "-"),
(0xFF0E, "."),
(0xFF1A, ":"),
(0xFF1B, ";"),
(0xFF1C, "<"),
(0xFF1E, ">"),
(0xFF1F, "?"),
(0xFF3B, "["),
(0xFF3C, "\\"),
(0xFF3D, "]"),
(0xFF3E, "^"),
(0xFF3F, "_"),
(0xFF40, "`"),
(0xFF5B, "{"),
(0xFF5C, "|"),
(0xFF5D, "}"),
(0xFFE0, "¢"),
(0xFFE1, "£"),
(0xFFE2, "¬"),
(0xFFE4, "¦"),
(0xFFE5, "¥"),
];
pub fn compatibility_expansion(c: char) -> Option<&'static str> {
let cp = c as u32;
COMPATIBILITY_EXPANSIONS
.binary_search_by_key(&cp, |&(k, _)| k)
.ok()
.map(|i| COMPATIBILITY_EXPANSIONS[i].1)
}
pub fn expand_compatibility(word: &str) -> Option<String> {
if !word.chars().any(|c| compatibility_expansion(c).is_some()) {
return None;
}
let mut out = String::with_capacity(word.len());
for c in word.chars() {
match compatibility_expansion(c) {
Some(e) => out.push_str(e),
None => out.push(c),
}
}
Some(out)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn squared_units_and_letterlike_expand() {
assert_eq!(compatibility_expansion('㎏'), Some("kg"));
assert_eq!(compatibility_expansion('㎐'), Some("Hz"));
assert_eq!(compatibility_expansion('℃'), None);
assert_eq!(compatibility_expansion('ffl'), Some("ffl"));
assert_eq!(compatibility_expansion('™'), None);
assert_eq!(compatibility_expansion('№'), None);
assert_eq!(compatibility_expansion('a'), None);
assert_eq!(compatibility_expansion('a'), None);
assert_eq!(compatibility_expansion('你'), None);
}
#[test]
fn expansion_is_all_or_nothing_per_word() {
assert_eq!(expand_compatibility("abc"), None);
assert_eq!(expand_compatibility("5㎏").as_deref(), Some("5kg"));
}
#[test]
fn table_is_sorted_and_nonempty() {
assert!(COMPATIBILITY_EXPANSIONS.len() > 150);
assert!(COMPATIBILITY_EXPANSIONS.windows(2).all(|w| w[0].0 < w[1].0));
}
}