Skip to content
Theory · Strings · lesson 3 of 10

String methods

At the till you can do a lot with a receipt. You can find the line with bread on it, reprint the heading in capital letters, cut off the advert at the bottom. But the cashier never edits the receipt itself. They print a new one with the changes, and the old one stays as it was.

A string has ready-made methods for such actions. You call them with a dot after the string, like Length, only with parentheses at the end: raw.Trim(). Each method returns a result: a new string, a number or a bool. The original string stays the same:

C#
string raw = "  Hello, World  ";
string text = raw.Trim();
Console.WriteLine(text);           // Hello, World
Console.WriteLine(text.ToUpper()); // HELLO, WORLD
Console.WriteLine(text.ToLower()); // hello, world
Console.WriteLine(raw.Length);     // 16
Console.WriteLine(text.Length);    // 12

Let's go through the example line by line:

  1. raw.Trim() returns a copy of the string without the spaces at its edges, and it goes into text.
  2. text.ToUpper() returns the same text in capital letters.
  3. text.ToLower() returns it in small letters.
  4. raw.Length is still 16: Trim did not touch raw, and its edge spaces are still there.
  5. text has twelve characters: Trim does not remove the space between the words.

Case and spaces

ToUpper and ToLower

ToUpper turns every letter into a capital, and ToLower into a small letter. They leave digits, spaces and punctuation alone. These methods help when text must be brought to one form, for example before printing a heading.

Trim

Trim removes spaces, tabs and line breaks at the start and the end of a string. It touches nothing inside the string. If extra spaces get in the way on one side only, there is TrimStart for the start and TrimEnd for the end.

Searching

IndexOf

IndexOf looks for a character or a piece of text and returns the index of the first match. For text from the example, text.IndexOf("World") gives 7, and text.IndexOf('o') gives 4: the first o is in the word Hello. If there is no match, the method returns -1, like Array.IndexOf for an array.

The search is case-sensitive, so text.IndexOf("world") also gives -1.

Contains

Contains answers a simpler question: is the piece in the string at all. text.Contains("World") returns true, and text.Contains("world") returns false.

Cutting out a piece

Substring returns a part of the string. It has two forms:

  • Substring(start) runs from index start to the end of the string;
  • Substring(start, length) is a piece of length characters starting at index start.

They are often combined with IndexOf: first find the border, then cut. This is how the name and the domain come out of an email address:

C#
string email = "anna@mail.com";
int at = email.IndexOf('@');
Console.WriteLine(at);                      // 4
Console.WriteLine(email.Substring(0, at));  // anna
Console.WriteLine(email.Substring(at + 1)); // mail.com
Console.WriteLine(email.Substring(5, 4));   // mail
Console.WriteLine(email.IndexOf('#'));      // -1

Let's go step by step:

  1. @ stands at index 4, and this value goes into at.
  2. Substring(0, at) takes four characters from the start: anna.
  3. Substring(at + 1) takes everything after @: mail.com.
  4. Substring(5, 4) is four characters starting at index 5: mail. The second number is the length of the piece, not the index of its end.
  5. The address has no #, so IndexOf returns -1.

This is where the receipt and the string part ways. A piece cut off a receipt is gone from it, but Substring cuts nothing off: it copies some of the characters into a new string, and email stays whole.

A piece may end at the last character of the string: the start plus the length may equal the length of the string. If the sum is larger, Substring stops the program with an ArgumentOutOfRangeException.

Interviewers like to ask what the second argument of Substring means. In C# it is the length of the piece, while a similar method in Java and JavaScript takes the index of the end. People who come from those languages often mix them up.

Replacing

Replace replaces every occurrence of one piece with another and returns a new string. text.Replace("World", "C#") gives Hello, C#, and text.Replace('l', 'L') changes all three letters: HeLLo, WorLd.

Splitting and joining

Split

Split cuts a string at a separator character and returns an array of pieces, string[]. The separator itself does not go into the pieces. Two separators in a row give an empty piece: "a,,b".Split(',') returns three strings, and the middle one is the empty string "".

string.Join

You have already met string.Join in the theme on arrays. It does the opposite: it glues the elements of an array into one string and puts a separator between them. You call this method on the string type itself, not on a particular string: string.Join(", ", parts).

C#
string line = "red,green,blue";
string[] parts = line.Split(',');
Console.WriteLine(parts.Length);              // 3
Console.WriteLine(parts[1]);                  // green
Console.WriteLine(string.Join(" | ", parts)); // red | green | blue

Split(',') gave an array of three strings, and parts[1] is the second of them. string.Join glued them back, this time with |.

Common mistake

The second number of Substring was taken for the index of the end:

C#
string text = "Hello, World";
Console.WriteLine(text.Substring(7, 12)); // ✗
TEXT
Unhandled exception. System.ArgumentOutOfRangeException: Index and length must refer to a location within the string. (Parameter 'length')

The goal was to cut out World: it starts at index 7, and the string ends before index 12. But Substring read the second number as a length: 12 characters starting at index 7. The string has only 12 characters, and such a piece would run past its end.

The program compiles, and when it runs it stops at this line. You need a piece of length 5, text.Substring(7, 5), or the rest of the string, text.Substring(7).

Key points

  • String methods return a result, and the original string stays the same: Trim, ToUpper, ToLower and Replace give new strings.
  • IndexOf returns the index of the first match or -1, Contains returns true or false; both are case-sensitive.
  • Substring(start, length) takes length characters starting at start; the second number is a length, not the index of the end.
  • Split cuts a string into an array at a separator, and string.Join glues the array back.