# Text.Length, Text.IsEmpty, Text.IsBlank, Text.Contains, Text.StartsWith, Text.EndsWith

> Ask a string a question without changing it: its length, whether it is empty or blank, and whether it contains, starts with, or ends with a piece of text. The membership checks are ORDINAL and case-sensitive, and they take a literal piece of text — not a wildcard pattern. All run in memory.

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

## Summary        {#summary}
These are the read-only questions about a string. `Text.Length(s)` is its length; `Text.IsEmpty(s)` and
`Text.IsBlank(s)` test for emptiness; and `Text.Contains(s, part)`, `Text.StartsWith(s, part)`,
`Text.EndsWith(s, part)` test a string against a **literal** piece of text. The membership checks are
**ordinal** — case-sensitive, and the argument is plain text, not a pattern.

## Signature      {#signature}
```osy syntax
Text.Length(<string> s) -> int
Text.IsEmpty(<string> s) -> bool          // length is 0
Text.IsBlank(<string> s) -> bool          // empty, or only whitespace
Text.Contains(<string> s, <string> part) -> bool
Text.StartsWith(<string> s, <string> part) -> bool
Text.EndsWith(<string> s, <string> part) -> bool
```

## Description    {#description}

### Length is UTF-16 code units, not visible characters   {#length}
`Text.Length` counts **UTF-16 code units** (the C# `string.Length`), so an astral character outside the
Basic Multilingual Plane — an emoji, for instance — counts as **two**. `Text.Length("🎉")` is `2`, not `1`.
For plain text this is the character count you expect; the distinction only shows up on emoji and other
astral symbols.

### Empty vs blank   {#empty-vs-blank}
`Text.IsEmpty(s)` is true only for the zero-length string `""`. `Text.IsBlank(s)` is broader: it is true
for `""` **and** for a string that is entirely whitespace, using the full Unicode whitespace set — so an
ideographic space (`　`) or a no-break space (` `) counts as blank too, not just an ASCII space.

### Contains / StartsWith / EndsWith are ORDINAL and take a literal   {#ordinal-literal}
The match is **case-sensitive**: `Text.Contains("Hello World", "world")` is `false`. And the argument is a
**literal** run of text — a `%` or `_` in it is just that character, with no wildcard meaning. An empty
`part` is contained by everything: `Text.Contains(s, "")` is always `true`.

> **`Text.Contains(s, part)` and the member form `s.Contains(part)` are the same call.** The member spelling
> ([Contains, StartsWith, EndsWith](https://osysharp.com/reference/function/string-search/)) is just instance sugar — same ordinal, case-sensitive, literal semantics. Write
> whichever reads better. Both push into a query where the receiver is a column. For pattern matching on an in-hand
> string use [Regex](https://osysharp.com/reference/stdlib/regex/) — but only in memory; it has no query-predicate form.

All six run wherever they are needed — computed on a string already in hand, and (being pure) they run in the
browser with no round trip where a UI action needs them, or push into a query when the receiver is a column
([execution side](https://osysharp.com/reference/function/execution-side/)).

## Examples       {#examples}
```osy title="a field validator built from the inspection functions" test app=text-inspect
// Reject a blank required field, and flag anything past a length budget.
string CheckName(string name) {
  if (Text.IsBlank(name)) { return "required"; }
  if (Text.Length(name) > 40) { return "too long"; }
  return "ok";
}
```

```osy title="the exact answers, pinned" run app=text-inspect
[Test]
void Text_inspection_answers() {
  Assert.Equal("required", CheckName("   "));    // whitespace-only fails the blank check
  Assert.Equal("ok", CheckName("Ada Lovelace"));


  Assert.Equal(5, Text.Length("hello"));
  Assert.Equal(2, Text.Length("🎉"));            // UTF-16 code units — the emoji counts twice

  Assert.True(Text.IsEmpty(""));
  Assert.False(Text.IsEmpty(" "));               // a space is not empty…
  Assert.True(Text.IsBlank("   "));              // …but it is blank
  Assert.False(Text.IsBlank(" hi "));

  Assert.True(Text.Contains("Hello World", "World"));
  Assert.False(Text.Contains("Hello World", "world"));   // ordinal → case-sensitive
  Assert.True(Text.Contains("Hello", ""));               // everything contains the empty string
  Assert.True(Text.StartsWith("Hello", "He"));
  Assert.False(Text.StartsWith("Hello", "he"));
  Assert.True(Text.EndsWith("Hello", "lo"));
}
```

## See also       {#see-also}
- [Contains, StartsWith, EndsWith](https://osysharp.com/reference/function/string-search/) — the member-call spelling `s.Contains(x)`, the same ordinal-literal test as this
- [Regex](https://osysharp.com/reference/stdlib/regex/) — pattern matching, when a literal check is not enough
- [Text.Split](https://osysharp.com/reference/function/text-split/) · [Text.TitleCase](https://osysharp.com/reference/function/text-titlecase/) — the other in-memory string builtins
