Unicode grapheme cluster segmentation library for MoonBit (UAX #29)
English | ๆฅๆฌ่ช
| Layer | Problem | Solution |
|---|---|---|
| L1: UTF-16 encoding | str[i] operates at code unit level | MoonBit core iter() |
| L2: Grapheme cluster | Composite emoji span multiple code points | This library |
| L3: Display width | Full-width / half-width display widths | rami3l/unicodewidth |
moon add kawaz/graphemeimport {
"kawaz/grapheme",
}// Correct grapheme cluster counting
let family = @grapheme.graphemes("๐จโ๐ฉโ๐งโ๐ฆ")
println(family.length()) // 1
// Split, access, and slice
let view = @grapheme.graphemes("Hello๐ฏ๐ตWorld")
println(view.length()) // 11 (H,e,l,l,o,๐ฏ๐ต,W,o,r,l,d)
println(view[5].to_owned()) // "๐ฏ๐ต"
println(view[1:3].to_string()) // "el" (slice โ GraphemeView::to_string)
// Iteration
for cluster in view {
println(cluster)
}
// Lazy evaluation: fast when you only need the first few clusters
let first = @grapheme.grapheme_iter("very long text...").head()Note: == comparison is based on code point sequences. Unicode normalization (NFC/NFD) is not considered, so precomposed and decomposed forms of the same character are treated as different GraphemeViews.
| Input | graphemes() | grapheme_iter() |
|---|---|---|
| ASCII 13 chars | 0.96 us | โ |
| ASCII 1,000 chars | 66 us | 77 us (full scan) |
| Emoji ZWJ ร 10 | 5.4 us | โ |
| Flags ร 10 | 1.5 us | โ |
| CJK 67 chars | 4.9 us | 4.9 us (full scan) |
| Mixed real world | 2.6 us | 2.8 us (full scan) |
| First 10 only (1,000 chars) | 67 us (full scan) | 0.75 us |
pub struct GraphemeView {
// private fields
}impl Eq for GraphemeViewimpl Hash for GraphemeViewimpl Show for GraphemeViewUnicode grapheme cluster segmentation library for MoonBit (UAX #29)