# Case Folding and Normalization

> StringZilla for Go

The binding exposes codepoint counting, Unicode normalization, and full case folding over UTF-8 bytes.
Counts are scalar values, not bytes; normalization covers all four forms (`NFC`, `NFD`, `NFKC`, `NFKD`).

```go
sz.Utf8Count("你好世界")    // 4 codepoints
sz.Utf8Count("Hello🌍")     // 6 — the astral emoji is one scalar

sz.Utf8Normalize("é", sz.NFC)   // "e" + U+0301 → precomposed "é"
sz.Utf8Normalize("ﬁ", sz.NFKC)  // ligature "ﬁ" → "fi"
```

### Case Folding

These helpers apply full Unicode case folding.
Each takes a `validate` flag; when set, inputs are checked and `ErrInvalidUTF8` is returned for malformed UTF-8.

```go
var ErrInvalidUTF8 = errors.New("invalid UTF-8")

func Utf8CaseFold(str string, validate bool) (string, error)
func Utf8CaseInsensitiveFind(haystack, needle string, validate bool) (index int64, length int64, err error)
```

`Utf8CaseFold` returns the case-folded string; folding may expand the output, so `"ß"` becomes `"ss"`.
`Utf8CaseInsensitiveFind` returns the byte `index` and matched byte `length` of the first case-insensitive match, or `index == -1` when no match is found; an empty needle returns `0, 0`.

```go
folded, _ := sz.Utf8CaseFold("Straße", false) // "strasse"
idx, length, _ := sz.Utf8CaseInsensitiveFind("Hello WÖRLD", "wörld", false)
// idx == 6, length == 6
```

For repeated searches with the same needle, `Utf8CaseInsensitiveNeedle` prepares it once, over its own copy of the bytes.
It is safe for concurrent use, since searches only read it.

```go
type Utf8CaseInsensitiveNeedle struct { /* ... */ }

func NewUtf8CaseInsensitiveNeedle(needle string, validate bool) (*Utf8CaseInsensitiveNeedle, error)
func (n *Utf8CaseInsensitiveNeedle) FindIn(haystack string, validate bool) (index int64, length int64, err error)
```

```go
needle, _ := sz.NewUtf8CaseInsensitiveNeedle("wörld", false)
idx, length, _ := needle.FindIn("Hello WÖRLD", false)
```

`import "github.com/ashvardanian/stringzilla/golang"`

## NormalForm

NormalForm selects a Unicode normalization form for Utf8Normalize.

```go
type NormalForm int
```

- `NFD`: NFD is canonical decomposition.
- `NFC`: NFC is canonical decomposition followed by canonical composition.
- `NFKD`: NFKD is compatibility decomposition.
- `NFKC`: NFKC is compatibility decomposition followed by canonical composition.

## Utf8CaseInsensitiveNeedle

Utf8CaseInsensitiveNeedle is a needle prepared once for repeated case-insensitive UTF-8 searches.

```go
type Utf8CaseInsensitiveNeedle struct {
    // contains filtered or unexported fields
}
```

It is safe for concurrent use, as searches only read it.

## NewUtf8CaseInsensitiveNeedle

NewUtf8CaseInsensitiveNeedle prepares a reusable case-insensitive needle over its own copy of it.

```go
func NewUtf8CaseInsensitiveNeedle(
    needle string,
    validate bool,
) (*Utf8CaseInsensitiveNeedle, error)
```

If validate is true, the needle is validated as UTF-8.

## FindIn

FindIn searches for the prepared needle in haystack and returns byte offsets.

```go
func (n *Utf8CaseInsensitiveNeedle) FindIn(
    haystack string,
    validate bool,
) (index int64, length int64, err error)
```

## Utf8CaseFold

Utf8CaseFold applies full Unicode case folding to a UTF-8 string.

```go
func Utf8CaseFold(str string, validate bool) (string, error)
```

It can expand the output, as "ß" → "ss" does, so it allocates up to 3× the input byte size.

## Utf8CaseInsensitiveFind

Utf8CaseInsensitiveFind finds the first case-insensitive occurrence of `needle` in `haystack` using full Unicode case folding and returns byte offsets.

```go
func Utf8CaseInsensitiveFind(
    haystack, needle string,
    validate bool,
) (index int64, length int64, err error)
```

## Utf8Normalize

Utf8Normalize returns the string normalized to the requested Unicode form.

```go
func Utf8Normalize(str string, form NormalForm) string
```

Malformed bytes pass through unchanged. The destination is sized for the worst-case compatibility decomposition (18x); composing forms never exceed that bound.

