pub(crate) const COENG: char = '\u{17D2}';
pub(crate) const ROBAT: char = '\u{17CC}';
pub(crate) fn is_khmer_base(c: char) -> bool {
matches!(c as u32, 0x1780..=0x17B3)
}
pub(crate) fn is_khmer_combining(c: char) -> bool {
let o = c as u32;
matches!(o, 0x17B4..=0x17D1) || o == 0x17D3 || o == 0x17DD || matches!(o, 0x200C..=0x200D) }
pub fn is_khmer(c: char) -> bool {
matches!(c as u32, 0x1780..=0x17FF)
}
pub fn split_kcc(text: &str) -> Vec<String> {
let chars: Vec<char> = text.chars().collect();
let n = chars.len();
let mut clusters: Vec<String> = Vec::new();
let mut i = 0;
while i < n {
let c = chars[i];
if is_khmer_base(c) {
let start = i;
i += 1;
while i < n {
let d = chars[i];
if d == COENG && i + 1 < n {
i += 2;
} else if is_khmer_combining(d) {
i += 1;
} else {
break;
}
}
clusters.push(chars[start..i].iter().collect());
} else {
clusters.push(c.to_string());
i += 1;
}
}
clusters
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn keeps_base_with_subscripts_and_vowels() {
assert_eq!(split_kcc("ខ្មែរ"), vec!["ខ្មែ", "រ"]);
assert_eq!(split_kcc("ស្ត្រី"), vec!["ស្ត្រី"]);
}
#[test]
fn separates_non_khmer_scalars() {
assert_eq!(split_kcc("ab 1"), vec!["a", "b", " ", "1"]);
}
#[test]
fn classifies_khmer_block() {
assert!(is_khmer('ខ'));
assert!(!is_khmer('a'));
assert!(!is_khmer('1'));
}
}