# strings

> String utilities — search, slice, split, join, replace, trim, case, padding, classification, formatting, and a string builder.

# strings

The `strings` module collects everything you need to inspect, transform, and assemble text — searching, slicing, splitting, joining, trimming, case conversion, padding, classification, formatting, and an efficient string builder. Import it with `import strings`.

## Searching

| Function | Signature | Description |
| --- | --- | --- |
| `indexOf` | `strings.indexOf(s: string, sub: string) → int` | First index of `sub`, or -1 if absent |
| `lastIndexOf` | `strings.lastIndexOf(s: string, sub: string) → int` | Last index of `sub`, or -1 if absent |
| `contains` | `strings.contains(s: string, sub: string) → bool` | Whether `s` contains `sub` |
| `count` | `strings.count(s: string, sub: string) → int` | Non-overlapping occurrences of `sub` |
| `hasPrefix` | `strings.hasPrefix(s: string, prefix: string) → bool` | Whether `s` starts with `prefix` |
| `hasSuffix` | `strings.hasSuffix(s: string, suffix: string) → bool` | Whether `s` ends with `suffix` |

## Slicing

| Function | Signature | Description |
| --- | --- | --- |
| `slice` | `strings.slice(s: string, start: int, end: int) → string` | Byte slice from `start` to `end`; negative indices count from the end |
| `sub` | `strings.sub(s: string, start: int, length: int) → string` | Substring of `length` bytes from `start`; negative `start` counts from the end |

## Splitting

| Function | Signature | Description |
| --- | --- | --- |
| `split` | `strings.split(s: string, sep: string) → string[]` | Split on every occurrence of `sep` |
| `splitN` | `strings.splitN(s: string, sep: string, n: int) → string[]` | Split into at most `n` parts; -1 means unlimited |
| `fields` | `strings.fields(s: string) → string[]` | Split on any whitespace, discarding empty parts |
| `lines` | `strings.lines(s: string) → string[]` | Split on newlines, stripping trailing carriage returns |

## Joining

| Function | Signature | Description |
| --- | --- | --- |
| `join` | `strings.join(arr: string[], sep: string) → string` | Join array elements with `sep` |

## Replacement

| Function | Signature | Description |
| --- | --- | --- |
| `replace` | `strings.replace(s: string, old: string, new: string) → string` | Replace all occurrences of `old` |
| `replaceN` | `strings.replaceN(s: string, old: string, new: string, n: int) → string` | Replace first `n` occurrences; -1 replaces all |

## Trimming

| Function | Signature | Description |
| --- | --- | --- |
| `trim` | `strings.trim(s: string, cutset?: string) → string` | Trim whitespace, or the given cutset, from both ends |
| `trimLeft` | `strings.trimLeft(s: string, cutset: string) → string` | Trim cutset chars from the left |
| `trimRight` | `strings.trimRight(s: string, cutset: string) → string` | Trim cutset chars from the right |
| `trimPrefix` | `strings.trimPrefix(s: string, prefix: string) → string` | Remove `prefix` if present |
| `trimSuffix` | `strings.trimSuffix(s: string, suffix: string) → string` | Remove `suffix` if present |

## Case

| Function | Signature | Description |
| --- | --- | --- |
| `upper` | `strings.upper(s: string) → string` | Convert to uppercase |
| `lower` | `strings.lower(s: string) → string` | Convert to lowercase |
| `title` | `strings.title(s: string) → string` | Capitalize the first letter of each word |

## Padding and repetition

| Function | Signature | Description |
| --- | --- | --- |
| `padLeft` | `strings.padLeft(s: string, width: int, pad: string) → string` | Right-align in a field of `width` bytes |
| `padRight` | `strings.padRight(s: string, width: int, pad: string) → string` | Left-align in a field of `width` bytes |
| `repeat` | `strings.repeat(s: string, n: int) → string` | Repeat `s` `n` times |
| `reverse` | `strings.reverse(s: string) → string` | Reverse the rune order |

## Characters and codepoints

| Function | Signature | Description |
| --- | --- | --- |
| `char` | `strings.char(code: int) → string` | UTF-8 string for the given codepoint |
| `code` | `strings.code(s: string) → int` | Codepoint of the first rune, or -1 if empty |
| `byteAt` | `strings.byteAt(s: string, i: int) → int` | Raw byte 0-255 at byte index `i`, or -1 if out of range |
| `fromBytes` | `strings.fromBytes(arr: int[]) → string` | Build a string from byte values |
| `toBytes` | `strings.toBytes(s: string) → int[]` | Array of byte values 0-255 |
| `runeLen` | `strings.runeLen(s: string) → int` | Number of Unicode runes, not bytes |

## Classification

| Function | Signature | Description |
| --- | --- | --- |
| `isAlpha` | `strings.isAlpha(s: string) → bool` | All chars are Unicode letters |
| `isDigit` | `strings.isDigit(s: string) → bool` | All chars are ASCII digits 0-9 |
| `isAlphaNum` | `strings.isAlphaNum(s: string) → bool` | All chars are letters or digits |
| `isSpace` | `strings.isSpace(s: string) → bool` | All chars are whitespace |

## Formatting and conversion

| Function | Signature | Description |
| --- | --- | --- |
| `format` | `strings.format(template: string, args: string[]) → string` | Replace `{0}`, `{1}`, ... with the matching args |
| `toInt` | `strings.toInt(s: string) → int` | Parse a decimal integer, 0 on failure |
| `toFloat` | `strings.toFloat(s: string) → float` | Parse a float, 0.0 on failure |
| `matchGlob` | `strings.matchGlob(pattern: string, s: string) → bool` | Match a glob pattern with `*` and `?` |

## strings.builder

Building strings in a loop with `out = out + chunk` is O(n squared). The builder accumulates into one buffer for O(n) growth, then materializes the result once at the end.

| Function | Signature | Description |
| --- | --- | --- |
| `new` | `strings.builder.new() → int` | Allocate a builder, returns its handle |
| `write` | `strings.builder.write(id: int, s: any) → bool` | Append a value; false if the handle is unknown |
| `writeln` | `strings.builder.writeln(id: int, s: any) → bool` | Append a value followed by a newline |
| `toString` | `strings.builder.toString(id: int) → string` | Materialize the accumulated string |
| `len` | `strings.builder.len(id: int) → int` | Number of bytes accumulated |
| `reset` | `strings.builder.reset(id: int) → void` | Clear the buffer, keep the handle |
| `free` | `strings.builder.free(id: int) → bool` | Release the handle; true if it existed |

## Example

```goost
import strings

let parts = strings.split("a,b,c", ",")
let joined = strings.join(parts, " | ")
print(strings.upper(joined))            // A | B | C

let b = strings.builder.new()
strings.builder.write(b, "count=")
strings.builder.write(b, "42")
print(strings.builder.toString(b))      // count=42
strings.builder.free(b)
```