The segmentation primitive is allocation-free: it fills the caller’s span with segment lengths and returns the count. Segments tile the text, so each starts where the previous one ended.
long runeCount = Sz.CountRunes(text); // cf. counting System.Text.Rune
int decoded = Sz.Decode(text, codepoints); // fill a Span<int>; ill-formed or truncated -> U+FFFD
Span<long> lengths = stackalloc long[64];
int count = Sz.Segment(text, Sz.SegmentKind.Words, lengths); // UAX-29
ReadOnlySpan<byte> rest = text;
foreach (long length in lengths[..count]) {
Use(rest[..(int)length]);
rest = rest[(int)length..];
}
// Kinds: Graphemes (cf. StringInfo), Words, Sentences, LineBreaks (UAX-14)Codepoints count scalar values, not bytes or UTF-16 chars. Segmentation tiles the text — every byte belongs to exactly one segment — and a grapheme cluster can span several codepoints.
Sz.CountRunes("你好世界"u8); // 4 codepoints
Sz.CountRunes("Hello🌍"u8); // 6 — the astral emoji is one scalar
foreach (var cluster in Sz.EnumerateGraphemes("👍🏽🇺🇸"u8)) Use(cluster); // 2 clusters: 👍🏽 (emoji + skin tone), 🇺🇸 (flag)
foreach (var word in Sz.EnumerateWords("Hello, 世界"u8)) Use(word); // Latin run, then CJK run