# Case Folding and Normalization

> StringZilla for C#

Case folding fills a gap: .NET has no public Unicode case-folding API.

```csharp
byte[] folded = Sz.CaseFold("Straße"u8);              // -> "strasse"
long position = Sz.UncasedIndexOf(haystack, "WÖRLD"u8, out long matched); // caseless search

using UncasedNeedle needle = new("fox"u8); // prepared once, reusable across haystacks and threads
needle.IndexIn(document, out long matchedLength);

byte[] composed = Sz.Normalize(text, Sz.NormalForm.Nfc); // cf. string.Normalize
int written = Sz.Normalize(text, Sz.NormalForm.Nfc, destination); // allocation-free variant

Sz.Normalize("é"u8, Sz.NormalForm.Nfc);  // "e" + U+0301 -> precomposed "é"
Sz.Normalize("ﬁ"u8, Sz.NormalForm.Nfkc);       // ligature "ﬁ" -> "fi"
Sz.Normalize("Straße"u8, Sz.NormalForm.NfkcCasefold); // NFKC with case folding -> "strasse", for caseless keys
```

`using StringZilla;`

## UncasedNeedle

A case-folding search needle, prepared once to search many haystacks from any thread.

```csharp
class UncasedNeedle
```

Fills a gap: no .NET caseless UTF-8 search. Dispose to free the native copy.

## UncasedNeedle

Copies _needle_  into native memory and prepares it for caseless search.

```csharp
UncasedNeedle(ReadOnlySpan<byte> needle);
```

## IndexIn

First byte offset of this needle in _haystack_  (caseless), or -1.

```csharp
long IndexIn(ReadOnlySpan<byte> haystack, out long matchedLength);
```

## Dispose

Frees the native copy of the needle; calling it again does nothing.

```csharp
void Dispose();
```

