C# Strings

Work with text in C#: join and interpolate strings, use common methods like ToUpper, Contains, Replace, Split and Trim, format numbers, write escapes and raw strings, and build text efficiently with StringBuilder.

Lesson 4 of 43Beginner17 min read

Text is everywhere in software: names, messages, email addresses, file paths, search queries, JSON. In C#, text is stored in a string, a sequence of characters written in double quotes.

C# gives strings a rich set of built-in methods. You can change their case, search inside them, cut out parts, replace words, split a line of comma-separated values into pieces and join them back together. String interpolation, written with a $ before the opening quote, lets you drop variables and even calculations straight into text, with formatting for prices and dates.

One important detail: C# strings are immutable. Methods like ToUpper never change the original string; they return a new one. In this lesson you'll learn the most useful string methods, format numbers neatly, handle special characters, and use StringBuilder when you need to build a long piece of text step by step.

Creating and combining strings

C#
string first = "Ada";
string last = "Lovelace";
string full = first + " " + last;          // concatenation
string greeting = $"Hello, {first}!";      // interpolation
string sum = $"2 + 3 = {2 + 3}";           // expressions work too
  • full.Length gives the number of characters.
  • full[0] gives the first character, a char. Indexes start at 0, and full[^1] gives the last character.
  • Interpolation is easier to read than + when there are several values.

Common string methods

MethodExampleResult
ToUpper() / ToLower()"Hi".ToUpper()"HI"
Trim()" hi ".Trim()"hi"
Contains(x)"hello".Contains("ell")true
StartsWith(x) / EndsWith(x)"file.txt".EndsWith(".txt")true
IndexOf(x)"banana".IndexOf("n")2 (or -1 if not found)
Substring(start, length)"Codevra".Substring(0, 4)"Code"
Replace(a, b)"a-b-c".Replace("-", "+")"a+b+c"
Split(',')"a,b,c".Split(',')["a", "b", "c"]
string.Join(", ", items)string.Join("-", parts)"a-b-c"
string.IsNullOrWhiteSpace(s)string.IsNullOrWhiteSpace(" ")true

Formatting, escapes and raw strings

Add a format specifier after a colon inside interpolation braces:

  • {price:F2} gives two decimal places: 19.50.
  • {count:N0} adds thousands separators: 1,234,567.
  • {ratio:P0} shows a percentage: 75%.
  • {name,-10} pads to 10 characters, which lines up columns.

Escape sequences start with a backslash: \n new line, \t tab, \" a quote, \\ a backslash. A verbatim string, @"C:\files\data.txt", treats backslashes literally. Raw string literals, wrapped in three quotes """, can span lines and contain quotes without escaping, which is perfect for JSON samples.

Slicing with ranges and indexes

Besides Substring, modern C# lets you cut out part of a string with a range, written start..end. The start is included and the end is excluded, and ^ counts from the end:

C#
string word = "Codevra";
Console.WriteLine(word[..4]);    // Code   (first four characters)
Console.WriteLine(word[1..4]);   // ode    (indexes 1, 2 and 3)
Console.WriteLine(word[^3..]);   // vra    (last three characters)
Console.WriteLine(word[^1]);     // a      (last character, a char)

Ranges are often easier to read than Substring(start, length), because you write where to stop rather than how many characters to take. Both throw an ArgumentOutOfRangeException if you go past the end, so check Length first when the text comes from a user. The result of a range on a string is always a new string, because the original can never change, and the same syntax works on arrays.

Working with individual characters

A string is a sequence of char values, so you can loop over it with foreach and test each character with the static methods on char:

C#
int digits = 0;
foreach (char c in "Room 101")
{
    if (char.IsDigit(c)) digits++;
}
Console.WriteLine(digits);   // 3

Useful checks include char.IsLetter, char.IsDigit, char.IsWhiteSpace and char.IsUpper, and char.ToUpper('q') gives 'Q'. Each char is also a number underneath: (int)'A' is 65 and (char)66 is 'B'.

Because strings are immutable, you can't write word[0] = 'J'. When you need to change individual characters, copy them into an array, edit it and build a new string:

C#
char[] letters = "hello".ToCharArray();
letters[0] = 'j';
string changed = new string(letters);   // "jello"

new string('-', 10) is a related shortcut that repeats one character, which is handy for underlining headings in console output.

C# Strings Syntax

String operations

string s = "  Hello World  ";
s.Trim().ToLower()                // "hello world"
s.Contains("World")               // true
s.Trim().Split(' ')               // ["Hello", "World"]
string.Join(", ", new[] { "a", "b" })   // "a, b"
$"{price:F2}"   $"{big:N0}"   $"{share:P1}"
"line1\nline2"   @"C:\temp"   """He said "hi" """
var sb = new System.Text.StringBuilder();
sb.Append("a").AppendLine("b");
string result = sb.ToString();

C# Strings Summary

  • Strings are text in double quotes; $"...{x}..." interpolates values and expressions.
  • Length, indexing from 0 and ^1 for the last character.
  • ToUpper, Trim, Contains, IndexOf, Substring, Replace, Split and Join cover most tasks.
  • Format specifiers such as :F2 and :N0 control how numbers appear.
  • Strings are immutable; use StringBuilder to build long text in steps.

C# Strings Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Cleaning up a name

C#
string input = "   ada LOVELACE  ";
string trimmed = input.Trim();
string[] parts = trimmed.Split(' ');

string first = parts[0][0].ToString().ToUpper() + parts[0].Substring(1).ToLower();
string last = parts[1][0].ToString().ToUpper() + parts[1].Substring(1).ToLower();

Console.WriteLine($"[{trimmed}]");
Console.WriteLine($"{first} {last}");
Console.WriteLine($"Initials: {first[0]}{last[0]}");
Console.WriteLine($"Length: {first.Length + last.Length}");
Output
[ada LOVELACE]
Ada Lovelace
Initials: AL
Length: 11
Line-by-line explanation
  1. Line 2Trim removes spaces from both ends.
  2. Line 3Split breaks the text at each space into an array.
  3. Line 5The first letter is uppercased and the rest of the word lowercased.
  4. Line 10Indexing a string gives a char.
  5. Line 11Ada has 3 letters and Lovelace has 8.
Example 2

Formatting a receipt

C#
string[] items = { "Coffee", "Croissant", "Orange juice" };
decimal[] prices = { 2.8m, 2.25m, 3.5m };
decimal total = 0;

for (int i = 0; i < items.Length; i++)
{
    Console.WriteLine($"{items[i],-14}{prices[i],6:F2}");
    total += prices[i];
}
Console.WriteLine(new string('-', 20));
Console.WriteLine($"{"Total",-14}{total,6:F2}");
Console.WriteLine($"Visitors: {1234567:N0}");
Output
Coffee          2.80
Croissant       2.25
Orange juice    3.50
--------------------
Total           8.55
Visitors: 1,234,567
Line-by-line explanation
  1. Line 7,-14 pads the name to 14 characters on the left; ,6:F2 right-aligns the price in 6 characters with two decimals.
  2. Line 10new string('-', 20) repeats a character 20 times.
  3. Line 12N0 adds thousands separators (shown here with English formatting).
Example 3

Searching, replacing and StringBuilder

C#
using System.Text;

string email = "Ada.Lovelace@Example.com";
int at = email.IndexOf('@');
string user = email.Substring(0, at);
string domain = email[(at + 1)..].ToLower();

Console.WriteLine(user);
Console.WriteLine(domain);
Console.WriteLine(email.EndsWith(".com"));
Console.WriteLine(string.Equals(email, "ada.lovelace@example.com", StringComparison.OrdinalIgnoreCase));
Console.WriteLine("2026-03-01".Replace("-", "/"));

var sb = new StringBuilder();
for (int i = 1; i <= 3; i++)
{
    sb.Append($"Row {i}; ");
}
Console.WriteLine(sb.ToString().TrimEnd());
Output
Ada.Lovelace
example.com
True
True
2026/03/01
Row 1; Row 2; Row 3;
Line-by-line explanation
  1. Line 4IndexOf finds the position of the @ sign.
  2. Line 5Substring(0, at) takes everything before it.
  3. Line 6[(at + 1)..] is a range: everything after the @.
  4. Line 11OrdinalIgnoreCase compares without caring about capital letters.
  5. Lines 14 to 18StringBuilder adds pieces to one buffer instead of creating a new string each time.
  6. Line 19TrimEnd removes the trailing space.

Common C# Strings Mistakes

Expecting a method to change the string

Don't
string name = "ada";
name.ToUpper();
Console.WriteLine(name);            // still "ada"
Do
string name = "ada";
name = name.ToUpper();

Building a big string with += in a loop

Don't
string report = "";
foreach (var line in lines) report += line + "\n";   // slow for thousands of lines
Do
var sb = new StringBuilder();
foreach (var line in lines) sb.AppendLine(line);
string report = sb.ToString();

Backslashes in a normal string

Don't
string path = "C:\new\test.txt";    // \n and \t become a new line and a tab
Do
string path = @"C:\new\test.txt";

C# Strings in Real Projects

Strings in applications

Web APIs trim and validate form fields, compare emails ignoring case, and build messages with interpolation. Import tools split CSV lines with Split(','). Logging libraries use interpolation-style templates, and report generators use StringBuilder to assemble large documents. Raw string literals keep JSON and SQL samples readable in tests.

C# Strings FAQ

How do I check if a string is empty or null in C#?

Use string.IsNullOrEmpty(s) to catch both null and "", or string.IsNullOrWhiteSpace(s) to also treat strings made only of spaces as empty. The second is usually the better choice for user input. Checking s.Length == 0 on its own throws a NullReferenceException when s is null.

What is the difference between string interpolation and string.Format?

Both produce the same text. Interpolation, $"Total: {total:F2}", puts the values directly inside the braces, while string.Format("Total: {0:F2}", total) uses numbered placeholders and a separate argument list. Interpolation is easier to read and is the usual choice in modern C#.

How do I split a string and ignore empty entries?

Pass StringSplitOptions.RemoveEmptyEntries: "a,b,,c".Split(',', StringSplitOptions.RemoveEmptyEntries) gives three items instead of four. Add StringSplitOptions.TrimEntries as well, combined with |, to remove spaces around each piece.

Why can't I change a character in a C# string?

Strings are immutable, so the indexer s[0] is read-only and s[0] = 'X' doesn't compile. Build a new string instead, for example with Replace, with ranges and concatenation, or by editing a char[] from ToCharArray() and passing it to new string(...). For lots of changes, use StringBuilder.

When should I use StringBuilder instead of +?

Use StringBuilder when you build a string in a loop or from many pieces, because each + creates a brand-new string and copies everything so far. For joining a few values on one line, + or interpolation is perfectly fine and easier to read.

C# Strings Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Complete the code so the message includes the name.

string name = "Sam";
Console.WriteLine("Hi {name}");
Predict the outputeasy

What does this print?

Console.WriteLine("banana".IndexOf("n"));
Predict the outputmedium

What does this print?

string s = "a,b,,c";
Console.WriteLine(s.Split(',').Length);
Multiple choicemedium

What does $"{9.5:F2}" produce?

Multiple choicehard

Why is StringBuilder faster than += when building a long string in a loop?

C# Strings Quiz

5 questions to check what you learned.

  1. What does "Hello".Length return?

    • 4
    • 5
    • 6
    • "Hello"
  2. How do you compare two strings ignoring case?

    • a == b
    • string.Equals(a, b, StringComparison.OrdinalIgnoreCase)
    • a.Compare(b)
    • a.ToUpper() = b
  3. What does @ before a string literal do?

    • Interpolates values
    • Makes it a char
    • Makes it constant
    • Makes a verbatim string where backslashes are literal
  4. What does "Codevra".Substring(4) return?

    • "Code"
    • "evra"
    • "vra"
    • "v"
  5. What does "abc"[^1] give?

    • 'c'
    • 'a'
    • 'b'
    • An error