use unicode_normalization::UnicodeNormalization;
use unicode_segmentation::UnicodeSegmentation;
#[inline]
pub fn count_graphemes(text: &str) -> u32 {
UnicodeSegmentation::graphemes(text, true).count() as u32
}
#[inline]
pub fn count_code_points(text: &str) -> u32 {
text.chars().count() as u32
}
pub fn normalize_text(text: &str) -> String {
let normalized = text.nfc().collect::<String>();
normalized
.split_whitespace()
.collect::<Vec<&str>>()
.join(" ")
}
pub fn join_text_fragments(fragments: Vec<String>) -> String {
let joined = fragments.join(" ");
normalize_text(&joined)
}
pub fn detect_primary_script(text: &str) -> &'static str {
let latin_chars = text
.chars()
.filter(|c| c.is_ascii() || matches!(c, 'À'..='ÿ'))
.count();
let cjk_chars = text
.chars()
.filter(|c| matches!(c, '\u{3000}'..='\u{9FFF}'))
.count();
let cyrillic_chars = text
.chars()
.filter(|c| matches!(c, '\u{0400}'..='\u{04FF}'))
.count();
if cjk_chars > latin_chars && cjk_chars > cyrillic_chars {
"Han"
} else if cyrillic_chars > latin_chars && cyrillic_chars > cjk_chars {
"Cyrillic"
} else {
"Latin"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_count_graphemes() {
assert_eq!(count_graphemes("hello"), 5);
assert_eq!(count_graphemes("café"), 4);
assert_eq!(count_graphemes("こんにちは"), 5);
assert_eq!(count_graphemes("👩💻"), 1);
}
#[test]
fn test_count_code_points() {
assert_eq!(count_code_points("hello"), 5);
assert_eq!(count_code_points("café"), 4);
assert_eq!(count_code_points("こんにちは"), 5);
assert_eq!(count_code_points("\u{1F469}\u{200D}\u{1F4BB}"), 3); }
#[test]
fn test_normalize_text() {
assert_eq!(normalize_text("café"), "café");
let nfd = "cafe\u{0301}"; assert_eq!(normalize_text(nfd), "café");
assert_eq!(normalize_text(" hello world "), "hello world");
assert_eq!(normalize_text("hello\n\t world"), "hello world");
}
#[test]
fn test_join_text_fragments() {
let fragments =
vec!["Hello".to_string(), "world".to_string(), "!".to_string()];
assert_eq!(join_text_fragments(fragments), "Hello world !");
let fragments = vec![
" Text ".to_string(),
" with ".to_string(),
" extra ".to_string(),
" spaces ".to_string(),
];
assert_eq!(join_text_fragments(fragments), "Text with extra spaces");
}
#[test]
fn test_detect_primary_script() {
assert_eq!(detect_primary_script("Hello world"), "Latin");
assert_eq!(detect_primary_script("Привет мир"), "Cyrillic");
assert_eq!(detect_primary_script("こんにちは世界"), "Han");
assert_eq!(detect_primary_script("Hello 世界 and more Latin"), "Latin");
}
}