Skip to main content

C# String Formatting

String formatting is an essential skill for any C# developer. It allows you to create well-structured, readable text output by combining strings with variables and controlling how they're displayed. Whether you're building console applications, web services, or desktop apps, effective string formatting will make your code more readable and your outputs more professional.

Introduction to String Formatting

In C#, there are several ways to format strings:

  1. String concatenation
  2. String interpolation
  3. Composite formatting with string.Format()
  4. StringBuilder for complex string operations

Each approach has its advantages and ideal use cases, which we'll explore in this guide.

String Concatenation

The simplest way to combine strings is using the + operator:

csharp
string firstName = "John";
string lastName = "Doe";
string fullName = firstName + " " + lastName;
Console.WriteLine(fullName); // Output: John Doe

While simple, concatenation becomes inefficient when combining many strings or when used in loops.

String Interpolation

Introduced in C# 6, string interpolation is a clean, readable way to embed variables directly within a string. You prefix the string with $ and place expressions within {}:

csharp
string firstName = "John";
string lastName = "Doe";
int age = 30;
string message = $"Hello, my name is {firstName} {lastName} and I am {age} years old.";
Console.WriteLine(message);
// Output: Hello, my name is John Doe and I am 30 years old.

Formatting Numeric Values

You can format numbers within interpolated strings:

csharp
double price = 123.45;
Console.WriteLine($"Price: {price:C}"); // Output: Price: $123.45 (in US culture)
Console.WriteLine($"Price rounded: {price:F1}"); // Output: Price rounded: 123.5
Console.WriteLine($"Price with 2 decimals: {price:0.00}"); // Output: Price with 2 decimals: 123.45

Padding and Alignment

You can control spacing and alignment:

csharp
string[] fruits = { "Apple", "Banana", "Orange" };
decimal[] prices = { 1.2m, 0.85m, 2.0m };

Console.WriteLine($"{"Fruit",-10}{"Price",10}");
Console.WriteLine(new string('-', 20));

for (int i = 0; i < fruits.Length; i++)
{
Console.WriteLine($"{fruits[i],-10}{prices[i]:C,10}");
}

/* Output:
Fruit Price
--------------------
Apple $1.20
Banana $0.85
Orange $2.00
*/

The negative value -10 left-aligns with 10 character width, while positive 10 right-aligns.

Composite Formatting

Before string interpolation, the main approach was composite formatting using string.Format():

csharp
string firstName = "Jane";
string lastName = "Smith";
int age = 28;
string message = string.Format("Hello, my name is {0} {1} and I am {2} years old.",
firstName, lastName, age);
Console.WriteLine(message);
// Output: Hello, my name is Jane Smith and I am 28 years old.

The {0}, {1}, and {2} are placeholders that get replaced by the values provided.

Format Specifiers

Format specifiers control how values appear:

csharp
double number = 1234.5678;
DateTime date = new DateTime(2023, 10, 15);

// Numeric formats
Console.WriteLine(string.Format("Currency: {0:C}", number)); // $1,234.57
Console.WriteLine(string.Format("Exponential: {0:E}", number)); // 1.234568E+003
Console.WriteLine(string.Format("Fixed-point: {0:F2}", number)); // 1234.57
Console.WriteLine(string.Format("General: {0:G}", number)); // 1234.5678
Console.WriteLine(string.Format("Number: {0:N}", number)); // 1,234.57
Console.WriteLine(string.Format("Percent: {0:P}", number/100)); // 12.35%
Console.WriteLine(string.Format("Hexadecimal: {0:X}", 255)); // FF

// Date formats
Console.WriteLine(string.Format("Short date: {0:d}", date)); // 10/15/2023
Console.WriteLine(string.Format("Long date: {0:D}", date)); // Sunday, October 15, 2023
Console.WriteLine(string.Format("Short time: {0:t}", date)); // 12:00 AM
Console.WriteLine(string.Format("Long time: {0:T}", date)); // 12:00:00 AM
Console.WriteLine(string.Format("Month: {0:MMM}", date)); // Oct

StringBuilder for Complex String Operations

When you need to perform many string operations, especially in loops, StringBuilder is more efficient than concatenation:

csharp
using System.Text;

StringBuilder sb = new StringBuilder();
sb.Append("Hello ");
sb.Append("World");
sb.AppendLine("!");
sb.AppendFormat("The time is {0:t}", DateTime.Now);

string result = sb.ToString();
Console.WriteLine(result);
/*
Output:
Hello World!
The time is 3:45 PM
*/

Real-world Applications

Formatting a Receipt

csharp
string FormatReceipt(string storeName, string[] items, decimal[] prices, decimal taxRate)
{
StringBuilder receipt = new StringBuilder();

receipt.AppendLine($"*** {storeName} ***");
receipt.AppendLine($"Date: {DateTime.Now:MM/dd/yyyy hh:mm tt}");
receipt.AppendLine("---------------------------");

decimal subtotal = 0;
for (int i = 0; i < items.Length; i++)
{
receipt.AppendLine($"{items[i],-20}{prices[i],10:C}");
subtotal += prices[i];
}

decimal tax = subtotal * taxRate;
decimal total = subtotal + tax;

receipt.AppendLine("---------------------------");
receipt.AppendLine($"{"Subtotal",-20}{subtotal,10:C}");
receipt.AppendLine($"{"Tax",-20}{tax,10:C}");
receipt.AppendLine($"{"Total",-20}{total,10:C}");
receipt.AppendLine("---------------------------");
receipt.AppendLine("Thank you for your business!");

return receipt.ToString();
}

// Usage
string[] purchasedItems = { "Coffee", "Bagel", "Orange Juice" };
decimal[] itemPrices = { 3.50m, 2.75m, 4.25m };
Console.WriteLine(FormatReceipt("Morning Café", purchasedItems, itemPrices, 0.08m));

/* Output:
*** Morning Café ***
Date: 10/15/2023 03:45 PM
---------------------------
Coffee $3.50
Bagel $2.75
Orange Juice $4.25
---------------------------
Subtotal $10.50
Tax $0.84
Total $11.34
---------------------------
Thank you for your business!
*/

Formatting a Log Entry

csharp
string FormatLogEntry(string severity, string message, Exception exception = null)
{
string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");

if (exception != null)
{
return $"[{timestamp}] {severity}: {message}\nException: {exception.GetType().Name} - {exception.Message}\n{exception.StackTrace}";
}
else
{
return $"[{timestamp}] {severity}: {message}";
}
}

// Usage
Console.WriteLine(FormatLogEntry("INFO", "Application started"));
Console.WriteLine(FormatLogEntry("ERROR", "Failed to process file", new FileNotFoundException("Could not find file.txt")));

/* Output:
[2023-10-15 15:47:23.456] INFO: Application started
[2023-10-15 15:47:23.498] ERROR: Failed to process file
Exception: FileNotFoundException - Could not find file.txt
at Program.<Main>$(String[] args) in C:\Projects\Program.cs:line 25
*/

String Format Providers and Cultures

You can use IFormatProvider to control formatting based on different cultures:

csharp
using System.Globalization;

double price = 1234.56;
DateTime date = new DateTime(2023, 10, 15);

// US culture
CultureInfo us = new CultureInfo("en-US");
Console.WriteLine($"US Price: {price.ToString("C", us)}"); // US Price: $1,234.56
Console.WriteLine($"US Date: {date.ToString("D", us)}"); // US Date: Sunday, October 15, 2023

// German culture
CultureInfo de = new CultureInfo("de-DE");
Console.WriteLine($"German Price: {price.ToString("C", de)}"); // German Price: 1.234,56 €
Console.WriteLine($"German Date: {date.ToString("D", de)}"); // German Date: Sonntag, 15. Oktober 2023

// Japanese culture
CultureInfo jp = new CultureInfo("ja-JP");
Console.WriteLine($"Japanese Price: {price.ToString("C", jp)}"); // Japanese Price: ¥1,235
Console.WriteLine($"Japanese Date: {date.ToString("D", jp)}"); // Japanese Date: 2023年10月15日

Summary

String formatting in C# provides powerful tools to create well-structured, readable text. In this guide, we covered:

  • String concatenation for simple combinations
  • String interpolation with $"..." for readable, inline formatting
  • Composite formatting with string.Format() and format specifiers
  • StringBuilder for efficient complex string operations
  • Format providers for culture-specific formatting

When deciding which approach to use:

  • Use string interpolation ($"...") for most scenarios due to its readability
  • Use string.Format() when you need to store format strings separately
  • Use StringBuilder when building strings in loops or with many operations
  • Always be mindful of culture-specific formatting when working with international applications

Exercises

  1. Create a method that formats a product description with name, price, and discount percentage.
  2. Write a function that generates an HTML table from a list of string arrays.
  3. Create a program that displays calendar events in different time zones with proper formatting.
  4. Implement a custom number formatting function that adds thousand separators and limits decimal places.
  5. Create a function that formats phone numbers according to different country standards.

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)