# Text.TitleCase

> Capitalises the first letter of each word and lower-cases the rest, leaving a word that is already entirely upper-case untouched so acronyms survive. Word breaks fall on any non-letter except the apostrophe, so "o'brien" becomes "O'brien" but "mcdonald-smith" becomes "Mcdonald-Smith".

<!-- id: function-text-titlecase · area: function · stability: stable · html: https://osysharp.com/reference/function/text-titlecase/ -->

## Summary        {#summary}
`Text.TitleCase(s)` capitalises the first letter of each word in `s` and lower-cases the rest — except that a word
which is **already entirely upper-case is left exactly as it is**, so an acronym is not quietly mangled into
`Nasa`.

## Signature      {#signature}
```osy syntax
Text.TitleCase(<string> s) -> string
```

## Description    {#description}
A **word** is a run of letters, optionally containing an apostrophe. Every other character — a space, a hyphen, a
digit, a full stop — ends the word and starts a new one. That has two consequences worth knowing before you use it
on names:

| Input | Result | Why |
|---|---|---|
| `"hello world"` | `"Hello World"` | the ordinary case |
| `"NASA report"` | `"NASA report"` → `"NASA Report"` | an all-caps word is preserved |
| `"hELLO"` | `"Hello"` | a mixed-case word has its tail lower-cased |
| `"o'brien"` | `"O'brien"` | an apostrophe does **not** break a word |
| `"mcdonald-smith"` | `"Mcdonald-Smith"` | a hyphen **does** |
| `"3rd place"` | `"3Rd Place"` | a digit is not a letter, so `rd` begins a fresh word |

The last two rows are the ones that surprise people. `Text.TitleCase` is a mechanical transformation, not a
name-formatter: if you need `McDonald` or `3rd`, write the casing you want rather than deriving it.

Casing is **invariant** — it does not depend on the machine's locale, so the same input gives the same output
everywhere, and it gives the same output whether the function runs in the browser or on the server.

## Examples       {#examples}
```osy title="tidy up a user-entered display name" test app=text-search
string DisplayName(string raw) {
  return Text.TitleCase(Text.Trim(raw));
}
// DisplayName("  ada LOVELACE ")  ->  "Ada LOVELACE"
```

## See also       {#see-also}
- [Text.Split](https://osysharp.com/reference/function/text-split/) — the other in-memory string builtins
- [execution side](https://osysharp.com/reference/function/execution-side/) — why this runs in the browser, with no round trip
