use stringzilla::CaseSensitivity;use stringzilla::NormalForm;use stringzilla::Utf8UncasedNeedle;use stringzilla::Utf8UncasedNeedleArg;use stringzilla::Utf8UncasedMatches;use stringzilla::*;6.0.0-rc.1 · 91a27bdd
utf8_uncased_fold case-folds into a target buffer, utf8_norm applies a Unicode normal form, and utf8_find_denormalized checks conformance without rewriting.
utf8_uncased_fold applies Unicode case folding, for example ß → ss, returning the number of bytes written. utf8_norm normalizes to one of the five NormalForm variants: Nfd, Nfc, Nfkd, Nfkc, and NfkcCasefold, the Unicode toNFKC_Casefold that caseless search keys match on. utf8_find_denormalized is a fast check returning the byte offset of the first non-conforming byte, or None if already normalized:
use stringzilla::{self as sz, NormalForm};let mut dest = [0u8; 33];let len = sz::utf8_uncased_fold("HELLO WORLD", &mut dest).unwrap();assert_eq!(&dest[..len], b"hello world");// NFC check: a decomposed "café" (e + combining acute) violates NFC.assert!(sz::utf8_find_denormalized("cafe\u{0301}", NormalForm::Nfc).is_some());assert!(sz::utf8_find_denormalized("caf\u{00E9}", NormalForm::Nfc).is_none());let mut out = vec![0u8; "cafe\u{0301}".len() * 18];let n = sz::utf8_norm("cafe\u{0301}", NormalForm::Nfc, &mut out).unwrap();assert_eq!(&out[..n], "caf\u{00E9}".as_bytes());
The C kernels write without a capacity, so target buffers must hold the worst-case expansion whatever the input: source.len() * 3 for folding and source.len() * 18 for normalization.
A shorter one is refused with Status::UnexpectedDimensions before anything is written.
Returns Some((offset, match_length)), where the matched length may differ from the needle length due to case folding — ß matching SS, for instance.
A Utf8UncasedNeedle is prepared once and only read by every search, so one needle serves many haystacks and threads, and Utf8UncasedMatches iterates all matches as IndexSpans.
Matches start on codepoint boundaries: overlapping iteration and any zero-length match advance one codepoint, so an empty needle matches at every codepoint boundary, the end included, three times in "aé":
Canonical Decomposition. Decomposes precomposed characters into base + combining marks.
Nfc
1
Canonical Decomposition followed by Canonical Composition. The most common Unicode form.
Nfkd
2
Compatibility Decomposition. Decomposes ligatures and compatibility characters.
Nfkc
3
Compatibility Decomposition followed by Canonical Composition.
NfkcCasefold
4
NFKC with full case folding and without default-ignorable codepoints, the Unicode
toNFKC_Casefold that caseless identifiers and search keys are matched on.
Mirrors the C sz_utf8_uncased_needle_t: the needle's bytes, borrowed for 'a, and the folding
analysis Self::new runs once. Searches only read it, so one needle serves any number of
threads at once.
This iterator yields IndexSpan values representing the byte offset and length
of each match. The match length may differ from the needle length due to Unicode
case folding: "ß" matches "SS", as German eszett expands to two characters.
The iterator prepares the needle once, at construction. Matches start on codepoint boundaries:
overlapping iteration and any zero-length match advance one codepoint, so an empty needle
matches at every codepoint boundary, the end included.
Covers all four standard forms: NFD, NFC, NFKD, and NFKC. NFC is the most common form on the
web; NFD is useful for collation. Compatibility forms (NFKD/NFKC) additionally decompose
ligatures and compatibility characters (e.g., U+FB03 ffi → "ffi"), and NFKC_Casefold folds case
on top of NFKC, so "Straße" becomes "strasse".
Returns
Returns the number of bytes written to the target buffer.
Arguments
source: The UTF-8 string to normalize.
form: The Unicode normalization form to produce.
target: The target buffer to write the normalized string.
Errors
The C kernel writes without a capacity, so target must hold the worst-case expansion of
source.len() * 18 bytes whatever the input, or Status::UnexpectedDimensions is returned.
Examples
use stringzilla as sz;use sz::NormalForm;let source = "caf\u{00E9}"; // "café" NFC (precomposed é)let mut dest = vec![0u8; source.len() * 18];let len = sz::utf8_norm(source, NormalForm::Nfc, &mut dest).unwrap();assert_eq!(&dest[..len], "caf\u{00E9}".as_bytes()); // unchanged — already NFC
utf8_find_denormalizedReturns the byte offset of the first byte in source that violates the given Unicode Normal Form, or None if source is already in the requested form.
This is a fast check — it does not produce the normalized output. Use it to avoid an
unnecessary utf8_norm call when the input is likely already normalized.
Returns
None if source already conforms to form.
Some(offset) with the byte offset of the first offending byte otherwise.
Arguments
source: The UTF-8 string to inspect.
form: The normalization form to check against.
Examples
use stringzilla as sz;use sz::NormalForm;// NFD string (decomposed): base 'e' + combining acute U+0301let nfd = "cafe\u{0301}";assert!(sz::utf8_find_denormalized(nfd, NormalForm::Nfc).is_some());assert!(sz::utf8_find_denormalized("café", NormalForm::Nfc).is_none());
utf8_uncased_searchPerforms uncased search for needle in UTF-8 haystack.
Unlike ASCII uncased search, this handles Unicode case folding,
like German ß matching "ss" and Turkish İ matching "i".
Returns
If found, returns Some((offset, match_length)) where:
offset is the byte position in haystack where the match starts
match_length is the number of bytes matched in haystack, which may differ from
the needle length
Returns None if no match is found.
Arguments
haystack: The UTF-8 text to search in.
needle: The UTF-8 pattern to search for.
Examples
Basic usage with string slices:
use stringzilla as sz;let haystack = "Hello WORLD";if let Some((offset, len)) = sz::utf8_uncased_search(haystack, "world") { assert_eq!(offset, 6); assert_eq!(len, 5);}
With a prepared needle for repeated searches:
use stringzilla::{utf8_uncased_search, Utf8UncasedNeedle};let needle = Utf8UncasedNeedle::new(b"hello");// Analysed once in `new`, then only read by each searchlet result1 = utf8_uncased_search(b"Hello World", &needle);let result2 = utf8_uncased_search(b"HELLO there", &needle);assert_eq!(result1, Some((0, 5)));assert_eq!(result2, Some((0, 5)));
utf8_uncased_orderCompares two UTF-8 strings in uncased manner.
Uses Unicode case folding for comparison, handling characters like
German ß, Turkish İ/ı, and other case variants.
Returns
Ordering::Less if first < second
Ordering::Equal if first == second uncasedly
Ordering::Greater if first > second
Arguments
first: First UTF-8 string.
second: Second UTF-8 string.
Examples
use stringzilla as sz;use std::cmp::Ordering;assert_eq!(sz::utf8_uncased_order("Hello", "HELLO"), Ordering::Equal);assert_eq!(sz::utf8_uncased_order("abc", "ABD"), Ordering::Less);
utf8_uncased_foldApplies Unicode case folding to a UTF-8 string, writing the result to a target buffer.
Case folding normalizes text for uncased comparisons by mapping uppercase letters to their
lowercase equivalents and handling special cases like German U+00DF → ss expansion.
Returns
Returns the number of bytes written to the target buffer.
Arguments
source: The UTF-8 string to case-fold.
target: The target buffer to write the case-folded string.
Errors
The C kernel writes without a capacity, so target must hold the worst-case 3:1 expansion of
source.len() * 3 bytes whatever the input, or Status::UnexpectedDimensions is returned.
Examples
use stringzilla as sz;let source = "HELLO WORLD";let mut dest = [0u8; 33];let len = sz::utf8_uncased_fold(source, &mut dest).unwrap();assert_eq!(&dest[..len], b"hello world");