The same text can be encoded more than one way, and text that differs only in case often has to compare equal. normalize.h and case.h cover both. Each is an optional component, on by default; see Build options.
"é" is one code point, or "e" followed by a combining acute accent. muniNormalize puts text into one of the four normal forms of UAX #15: NFC and NFD for canonical equivalence, NFKC and NFKD also folding compatibility characters such as ligatures and full-width letters. Store and compare text in NFC.
muniCheckNormalization tells quickly whether text is already in a form: yes, no, or maybe (only normalizing tells). Most text already is, which saves the copy.
muniDecomposePair and muniComposePair work on single code points one level deep, the way shapers ask for them. muniGetDecomposition gives a code point's full NFD or NFKD, every mapping applied; an array of MUNI_MAX_DECOMPOSITION code points always holds it.
muniConvertCase lowercases, uppercases, titlecases or case folds text with the full mappings, which may change the length ("ß" uppercases to "SS"), and with the context rule of the final sigma. Titlecasing finds words by the word boundaries of UAX #29. A language selects extra rules:
muni_caseTurkic for Turkish and Azerbaijani: dotted and dotless i.muni_caseLithuanian: the dot of an i is kept under other accents.muni_caseGreek: uppercasing drops accents and breathings but keeps a dialytika, and adds one where a dropped accent kept two vowels apart ("Μάιος" uppercases to "ΜΑΪΟΣ"); the eta that means "or" keeps its accent when it stands alone ("ή" to "Ή"): no cased letter precedes or follows it past case-ignorable characters, the context of the final sigma, and a character both cased and case-ignorable, such as U+0345 or U+037A, counts as a cased letter there, where ICU skips it as case-ignorable; an iota subscript becomes a capital iota. Greek capitals are written this way; the default rules keep every accent. Lowercasing, titlecasing and folding are the default ones.muni_caseArmenian: the ligature "և" uppercases to "ԵՎ" and titlecases to "Եվ", as Eastern Armenian spells it, where the default rules give "ԵՒ" and "Եւ".muniGetLowercase, muniGetUppercase, muniGetTitlecase and muniFoldCase are the simple mappings of one code point; muniIsCased tells whether a code point has case.
To compare strings without regard to case, fold both and compare the results. To compare them as users see them, as UAX #31 compares identifiers, use muniGetNfkcCasefold: it folds case, turns compatibility forms into their plain selves, drops default ignorables such as a soft hyphen or a zero width space, and puts the result in NFC. It needs both components.
size_t keyLength = 0;
muniTextResult result =
muniGetNfkcCasefold(name, length, muni_convertStrict, key, sizeof(key), &keyLength);
// "Alice", "ALICE", a full-width "ALICE" and "Al" + soft hyphen + "ice"
// all get the key "alice".
MUNI_MAX_NORMALIZATION_SEGMENT (32) code points at once: a starter and the combining marks after it, once fully decomposed. That leaves 31 marks after a starter, and fewer when the starter itself decomposes (U+01D8 is u and two marks). Longer runs are refused with muni_errorLimit and the offset of the mark that makes the run too long; real text carries a handful, and UAX #15's stream-safe text at most 30. Skeletons and NFKC_Casefold share the limit.muniGetResultsVersion beside them and recompute them when it changes.