Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Understanding C# String Formatting and Format Specifiers

Tech May 13 2

Overview of String Formatting

C# provides powerful string formatting capabilities through the Format method and composite format strings. This guide covers the various format specifiers and their practical applications.

How Format Methods Process Format Strings

The Format method converts multiple objects into a single formatted string by following these steps:

  1. Placeholders like {0}, {1} in the format string get replaced with corresponding arguments in order
  2. When the parser encounters a placeholder, it checks if the corresponding argument implements IFormattable. If it does, the ToString method gets called with any format specifier present
  3. If the argument doesn't implement IFormattable, the method falls back to the type's native ToString() method, or Object.ToString() as a final option
var result = string.Format("Non-IFormattable: {0}, IFormattable: {1}", 
    new CustomType(), 42);
Console.WriteLine(result);

Standard Numeric Format Specifiers

Specifier Purpose Example Output
C Currency "{0:C3}", 2000 ¥2000.000
D Decimal "{0:D3}", 2000 2000
F Fixed-point "{0:F3}", 2000 2000.000
N Number with separators "{0:N}", 250000 250,000
P Percentage "{0:P3}", 0.29768 29.768
X Hexadecimal "{0:X4}", 12 C

String Class Utility Methods

Method Description
Equals(string value) Returns true if strings match exactly
Compare(string a, string b) Returns negative, zero, or positive based on comparison
IndexOf(string value) Returns position of first match, or -1 if not found
LastIndexOf(string value) Returns position of last match, or -1 if not found
Join(string separator, string[] values) Concatenates array elements with separator
Split(char separator) Returns string array split by delimiter
Substring(int start, int length) Extracts substring from start position
ToLower() Returns lowercase version
ToUpper() Returns uppercase version
Trim() Removes leading and trailing whitespace

Currency Formatting (C)

The C specifier converts numbers to currency format based on the current culture. The precision digit controls decimal places.

var amount = 100;
var formatted = $"{amount:C6}";
Console.WriteLine(formatted);

Output displays the currency symbol with six decimal places.

Decimal Formatting (D)

The D specifier converts integers to decimal representation with optional zero-padding.

var value = 100;
var padded = $"{value:D99}";
Console.WriteLine(padded);

This pads the number to 99 digits with leading zeros.

Numeric Separators (N)

The N specifier formats numbers with thousand separators and optional decimal precision.

var largeNumber = 1000000000;
var formatted = $"{largeNumber:N3}";
Console.WriteLine(formatted);

Output shows comma separators and three decimal places.

Percentage Formatting (P)

The P specifier multiplies by 100 and appends the percent symbol.

var ratio = 1;
var percentage = $"{ratio:P0}";
Console.WriteLine(percentage);

Displays as "100%" with zero decimal places.

Zero Placeholder (0)

The 0 specifier maintains minimum digit count, padding with zeros when necessary. Excess digits are preserved.

int value = 100;
var result = $"{value:00000}";
Console.WriteLine(result);

For decimal precision:

int amount = 1000000;
var formatted = $"{amount:00000.00}";
Console.WriteLine(formatted);

Rounding applies when the value exceeds the specified decimal places.

Digit Placeholder (#)

The # specifier reserves positions for optional digits. Leading and trailing zeros get omitted.

var code = 098804;
var clean = $"{code:####}";
Console.WriteLine(clean);

For decimals:

var price = 098804.15;
var result = $"{price:####.#}";
Console.WriteLine(result);

When decimal places exceed format specifiers, rounding occurs. Trailing zeros in the result get trimmed.

var value = 19884.049;
var output = $"{value:####.#}";
Console.WriteLine(output);

This produces "19884". The key difference: # placeholders suppress zeros, while 0 placeholders display them.

Alignment and Padding

Negative width values left-align, positive values right-align. Spaces fill the remaining width.

var data = "666";
var aligned = string.Format("{0,10}", data);
Console.WriteLine($"${aligned}$");

The PadLeft method achieves identical results:

var data = "666";
var padded = data.PadLeft(10);
Console.WriteLine($"${padded}$");

PadLeft supports custom padding characters, whereas alignment placeholders only work with spaces.

Right alignment:

var data = "666";
var aligned = string.Format("{0,-10}", data);
Console.WriteLine($"${aligned}$");

Use PadRight for similar functionality with custom characters.

Scientific Notation (E/e)

The E and e specifiers output exponential notation.

var value = 666;
var scientific = $"{value:e} {value:E}";
Console.WriteLine(scientific);

E produces uppercase output, while e produces lowercase.

Fixed-Point Formatting (F/f)

The F specifier converts to fixed-point decimal representation with configurable precision.

var number = -6666.66;
var result = $"{number:f6} {number:F3}";
Console.WriteLine(result);

Default precision is two decimal places unless explicitly specified.

General Formatting (G/g)

The G specifier selects between fixed-point and scientific notation based on which is more compact. Precision specifiers control significant digits.

Default precision varies by type:

  • Byte/SByte: 3 digits
  • Int16/UInt16: 5 digits
  • Int32/UInt32: 10 digits
  • Int64/UInt64: 19 digits
  • Single: 7 digits
  • Double: 15 digits
  • Decimal: 29 digits

Scientific notation only applies when exponent falls outside the -5 to +precision range.

Numeric Separator Formatting (N/n)

The N specifier combines thousand separators with decimal precision. Default shows two decimal places.

var value = -666;
var formatted = $"{value:N} {value:N6}";
Console.WriteLine(formatted);

Round-Trip Formatting (R/r)

The R specifier guarantees that a formatted number can be parsed back to the exact same value. Used exclusively with Single and Double types.

The algorithm first attempts standard format with maximum precision (15 digits for Double, 7 for Single). If parsing fails to recover the original value, higher precision gets used (17 and 9 digits respectively).

Hexadecimal Formatting (X/x)

The X specifier converts integers to hexadecimal representation.

var decimalValue = 255;
var hexUpper = $"{decimalValue:X}";
var hexLower = $"{decimalValue:x}";
Console.WriteLine($"{hexUpper} {hexLower}");

Precision specifiers control minimum digit count with zero-padding.

Date and Time Formatting

Standard Date/Time Format Specifiers

var flags = new[] { "G", "d", "D", "g", "M", "m", "s", "T", "t", "u", "U", "Y", "r", "R", "o", "O", "F", "f" };
var timestamp = DateTime.Now;
foreach (var flag in flags)
{
    Console.WriteLine($"{flag} -> {timestamp.ToString(flag)}");
}

Common specifiers:

  • d: Short date pattern
  • D: Long date pattern
  • T: Long time pattern
  • t: Short time pattern
  • Y: Year month pattern
  • s: ISO 8601 sortable format
  • u: Universal sortable format
  • o: ISO 8601 round-trip format

Custom date formatting:

var now = DateTime.Now;
var custom = $"{now:yyyy-MM-dd}";
Console.WriteLine(custom);

Custom Date/Time Format Specifiers

Specifier Description
d Day without leading zero (1-31)
dd Day with leading zero (01-31)
ddd Abbreviated day name
dddd Full day name
f Tenths of seconds (1 digit)
ff Hundredths (2 digits)
fff Milliseconds (3 digits)
ffff Ten-thousandths (4 digits)
M Month without leading zero (1-12)
MM Month with leading zero (01-12)
MMM Abbreviated month name
MMMM Full month name
h Hour in 12-hour format (1-12)
hh Hour with leading zero (01-12)
H Hour in 24-hour format (0-23)
HH Hour with leading zero (00-23)
m Minutes (0-59)
mm Minutes with leading zero (00-59)
s Seconds (0-59)
ss Seconds with leading zero (00-59)
y Year (1-2 digits)
yy Year with leading zero (2 digits)
yyyy Full year (4 digits)
z UTC offset in hours (no leading zero)
zz UTC offset with leading zero
zzz UTC offset with hours and minutes
K Timezone kind indicator

The F variant differs from f by omitting trailing zeros rather than displaying them.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.