Osy#betaRun it on Osyrin: osyrin.com

Reference / Function

Text.TrimStart, Text.TrimEnd, Text.PadStart, Text.PadEnd, PadLeft, PadRight

Text.TrimStart(s[, chars]) / TrimEnd(s[, chars]) → string · Text.PadStart(s, width, pad) / PadEnd(s, width, pad) → string · s.PadLeft(width[, char]) / s.PadRight(width[, char])

Trim whitespace from one end of a string, or pad it out to a width with a fill string. Trimming uses the full Unicode whitespace set. Padding never truncates — a string already at or over the width comes back unchanged — and the fill is a STRING, cut to fit the gap exactly. All run in memory.

stable3 examples compiled by CIfunctiontextstdlib

Summary#

Text.TrimStart(s) and Text.TrimEnd(s) remove whitespace from one end of a string (Text.Trim(s) does both). Give any of the three a second argument and it removes those CHARACTERS instead — C#'s TrimEnd(params char[]), with the set written as a string (a single char works too: s.TrimEnd('/')). Text.PadStart(s, width, pad) and Text.PadEnd(s, width, pad) grow a string to at least width characters by adding a fill on the left or right. Padding never shortens a string, and the fill may be a whole string. C#'s own names work too, exactly as C# writes them: s.PadLeft(5, '0'), s.PadRight(8) (a space fill).

Signature#

Text.TrimStart(<string> s) -> string          // strip leading whitespace
Text.TrimEnd(<string> s)   -> string          // strip trailing whitespace
Text.TrimStart(<string> s, <string> chars) -> string   // …or strip any of THESE characters
Text.TrimEnd(<string> s, <string> chars)   -> string
Text.Trim(<string> s, <string> chars)      -> string   // both ends
Text.PadStart(<string> s, <int> width, <string> pad) -> string   // fill on the LEFT to `width`
Text.PadEnd(<string> s, <int> width, <string> pad)   -> string   // fill on the RIGHT to `width`
s.PadLeft(<int> width[, <char> pad])  -> string    // C#'s name for PadStart — no pad is a SPACE
s.PadRight(<int> width[, <char> pad]) -> string    // C#'s name for PadEnd

Description#

Trimming characters rather than whitespace#

The second argument is a SET, not a suffix: every character in it is stripped from that end, repeatedly, exactly as C#'s char[] overload does. So TrimEnd("/") removes as many trailing slashes as there are, and TrimEnd("/\\") removes either kind.

string JoinUrl(string baseUrl, string path) {
  return Text.TrimEnd(baseUrl, "/") + "/" + Text.TrimStart(path, "/");
}

⚠ It is a set of characters, so TrimEnd(url, "/api") strips any trailing /, a, p or i — not the word "api". That is C#'s behaviour too, and it is the one thing about these overloads that surprises people.

Trimming uses the full Unicode whitespace set#

TrimStart/TrimEnd strip every leading/trailing whitespace character, not just the ASCII space — a tab, a newline, a no-break space ( ), an ideographic space ( ) are all removed. Only the named end is touched: Text.TrimStart(" hi ") is "hi " (trailing spaces survive).

Padding never truncates, and takes a WIDTH not a count-to-add#

width is the target length, not "how many characters to add". If the string is already at least that long it comes back unchanged: Text.PadStart("hello", 3, "0") is "hello". Otherwise the gap is filled to reach exactly width.

The pad is a STRING, cut to fit the gap#

The fill is repeated and then cut to exactly the deficit, so a multi-character pad can end mid-repeat: Text.PadStart("7", 3, "ab") fills two characters — "ab7" — and Text.PadEnd("7", 4, "ab") is "7aba". An empty pad is a no-op (it cannot fill anything), so Text.PadStart("x", 5, "") is "x" — it does not loop forever. For zero-padding a number, a format specifier like D5 or "00000" is usually clearer than padding a string — see format specifiers.

C#'s PadLeft / PadRight#

s.PadLeft(width, '0') and s.PadRight(width) are the SAME two verbs under C#'s names — PadLeft is PadStart, PadRight is PadEnd — and take C#'s arguments: a char fill, or none at all for a space. So the line a C# author writes compiles as written, and means what it meant there.

A character repeated: new string(c, n)#

C#'s new string('-', 40) — a rule, a bar of a given width, a column of filler — is the character n times, and it compiles as written (it is Text.Repeat over the character). A count of zero or less is the empty string.

All of these run in memory on a value already in hand, on the server and in the browser alike.

Examples#

// Trim stray whitespace, then right-justify into a fixed-width column with leading zeros.
string Ticket(string code) {
  return Text.PadStart(Text.TrimEnd(Text.TrimStart(code)), 6, "0");
}
[Test]
void Text_affix_answers() {
  Assert.Equal("000042", Ticket("  42  "));

  Assert.Equal("hi  ", Text.TrimStart("  hi  "));   // only the leading end
  Assert.Equal("  hi", Text.TrimEnd("  hi  "));
  Assert.Equal("hi", Text.TrimStart(" hi"));        // an ideographic space is whitespace too

  Assert.Equal("007", Text.PadStart("7", 3, "0"));
  Assert.Equal("ab7", Text.PadStart("7", 3, "ab"));  // multi-char pad, cut to the 2-char gap
  Assert.Equal("hello", Text.PadStart("hello", 3, "0"));   // already long enough → unchanged
  Assert.Equal("x", Text.PadStart("x", 5, ""));      // empty pad → no-op, never an infinite loop
  Assert.Equal("700", Text.PadEnd("7", 3, "0"));
  Assert.Equal("7aba", Text.PadEnd("7", 4, "ab"));

  Assert.Equal("00042", "42".PadLeft(5, '0'));     // C#'s names, C#'s arguments
  Assert.Equal("ab  |", "ab".PadRight(4) + "|");   // no fill → a space
  Assert.Equal("----", new string('-', 4));        // C#'s repeated-character constructor
}

See also#

Related

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…

Text.TitleCase

Capitalises the first letter of each word and lower-cases the rest, leaving a word that is already entirely upper-case…

format specifiers

Formats a number to a string with a .NET format specifier — F2 for two decimal places, N0 for a grouped whole number, C…