Post

C# - Composite Formatting

Introduction

Composite formatting uses numbered placeholders within a string.

  • At run time, everything inside the braces is resolved to a value that is also passed in based on their position.
  • This example of composite formatting uses a built-in method Format() on the string data type keyword.
1
2
3
4
5
6
string first = "Hello";
string second = "World";
string result = string.Format("{0} {1}!", first, second);
Console.WriteLine(result);

// Output: Hello World!
  • There are a few important things to notice about this code.
    • Data types and variables of a given data type have built-in "helper methods" to make certain tasks easy.
    • The literal string "{0} {1}!" forms a template, parts of which are replaced at run time.
    • The token {0} is replaced by the first argument after the string template, in other words, the value of the variable first.
    • The token {1} is replaced by the second argument after the string template, in other words, the value of the variable second.
  • You may think it’s odd to start with the number 0.
  • Actually this is very common in software development.
  • Whenever there’s a sequence of items that can be identified using a number, the numbering will usually start at 0.
  • If you update the code as follows:
1
2
3
4
5
6
7
string first = "Hello";
string second = "World";
Console.WriteLine("{1} {0}!", first, second);
Console.WriteLine("{0} {0} {0}!", first, second);

// Output: World Hello!
// Output: Hello Hello Hello!
  • A few observations about these examples:
    • For the first Console.WriteLine() statement, observe that the tokens can be arranged in any order.
    • The sample code has {1} before {0}.
    • For the second Console.WriteLine() statement, observe that the tokens can be reused with three instances of {0}.
    • Also, the second variable argument, second, isn’t used. Yet, the code still runs without error.

What is string interpolation?

  • String interpolation is a technique that simplifies composite formatting.
  • Instead of using a numbered token and including the literal value or variable name in a list of arguments to String.Format() or Console.WriteLine(), you can just use the variable name inside of the curly braces.
  • In order for a string to be interpolated, you must prefix it with the $ directive.
  • Now, create the same examples from earlier using string interpolation instead of composite formatting.
  • Update your code as follows:
1
2
3
4
5
6
7
8
9
string first = "Hello";
string second = "World";
Console.WriteLine($"{first} {second}!");
Console.WriteLine($"{second} {first}!");
Console.WriteLine($"{first} {first} {first}!");

// Output: Hello World!
// Output: World Hello!
// Output: Hello Hello Hello!
  • If you look at code examples in books and online, you’re likely to see both composite formatting and string interpolation used, but generally you should choose string interpolation.

Formatting currency

  • Composite formatting and string interpolation can be used to format values for display given a specific language and culture.
  • In the following example, the :C currency format specifier is used to present the price and discount variables as currency.
  • Update your code as follows:
1
2
3
4
5
decimal price = 123.45m;
int discount = 50;
Console.WriteLine($"Price: {price:C} (Save {discount:C})");

// Output: Price: $123.45 (Save $50.00)
  • Notice how adding the :C to the tokens inside of the curly braces formats the number as currency regardless of whether you use int or decimal.
  • What happens if your country/region and language isn’t known?
  • If you run the previous code in the “in-browser” .NET Editor, such as at TrydotNet you’ll see the following output: Price: ¤123.45 (Save ¤50.00).
  • The symbol ¤ is used instead of the symbol for your country/region’s money.
  • This is a generic symbol used to denote "currency" regardless of the type of currency.
  • You see this symbol in the .NET Editor because it ignores your current location.

How the user’s country/region and language affect string formatting

  • What if you execute the previous code on a computer in France that has its Windows Display Language set to French?
  • In that case you would see the following output.
1
Price: 123,45 € (Save 50,00 €)
  • The reason for the previous “€” output is that the string currency formatting feature is dependent on the local computer setting for culture.
  • In this context, the term “culture” refers to the country/region and language of the end user.
  • The culture code is a five character string that computers use to identify the location and language of the end user.
  • The culture code ensures certain information like dates and currency can be presented properly.

For example:

  • the culture code of an English speaker in the USA is en-US.
  • the culture code of a French speaker in France is fr-FR.
  • the culture code of a French speaker in Canada is fr-CA.
  • The culture affects the writing system, the calendar that’s used, the sort order of strings, and formatting for dates and numbers (like formatting currency).
  • Unfortunately, making sure your code works correctly on all computers regardless of the country/region or the end user’s language is challenging.
  • This process is known as localization (or globalization).
  • Localization depends on many factors not discussed in this note, but simply, the string formatting syntax might use a different format depending on the user’s culture.

Formatting numbers

  • When working with numeric data, you might want to format the number for readability by including commas to delineate thousands, millions, billions, and so on.
  • The N numeric format specifier makes numbers more readable.
  • Update your code as follows:
1
2
3
4
decimal measurement = 123456.78912m;
Console.WriteLine($"Measurement: {measurement:N} units");

// Output: Measurement: 123,456.79 units

Formatting percentages

  • Use the P format specifier to format percentages and rounds to 2 decimal places.
  • Add a number afterwards to control the number of values displayed after the decimal point.
  • Update your code as follows:
1
2
3
4
decimal tax = .36785m;
Console.WriteLine($"Tax rate: {tax:P2}");

// Output: Tax rate: 36.79%

Combining formatting approaches

  • String variables can store strings created using formatting techniques.
  • In the following example, decimals and decimal math results are formatted and stored in the yourDiscount string using composite formatting.
1
2
3
4
5
6
7
8
decimal price = 67.55m;
decimal salePrice = 59.99m;

string yourDiscount = String.Format("You saved {0:C2} off the regular {1:C2} price. ", (price - salePrice), price);

Console.WriteLine(yourDiscount);

// Output: You saved $7.56 off the regular $67.55 price.
  • You can combine multiple formatted strings.
  • Build on the previous code concatenating the calculated percentage using the string interpolation instead of string concatenation by inserting yourDiscount += $"A discount of {(price - salePrice)/price:P2}!"; into the code on the line before Console.WriteLine().
  • You don’t need to use String.Format() with this string interpolation approach.
  • Update your code as follows:
1
2
3
4
5
6
7
8
9
decimal price = 67.55m;
decimal salePrice = 59.99m;

string yourDiscount = String.Format("You saved {0:C2} off the regular {1:C2} price. ", (price - salePrice), price);

yourDiscount += $"A discount of {((price - salePrice)/price):P2}!"; //inserted
Console.WriteLine(yourDiscount);

// Output: You saved $7.56 off the regular $67.55 price. A discount of 11.19%!

Examples

1
2
3
4
5
6
7
8
9
10
11
int invoiceNumber = 1201;
decimal productShares = 25.4568m;
decimal subtotal = 2750.00m;
decimal taxPercentage = .15825m;
decimal total = 3185.19m;

Console.WriteLine($"Invoice Number: {invoiceNumber}");
Console.WriteLine($"   Shares: {productShares:N3} Product");
Console.WriteLine($"     Sub Total: {subtotal:C}");
Console.WriteLine($"           Tax: {taxPercentage:P2}");
Console.WriteLine($"     Total Billed: {total:C}");
  • The output of the previous code is as follows:
1
2
3
4
5
Invoice Number: 1201
   Shares: 25.457 Product
     Sub Total: $2,750.00
           Tax: 15.83%
     Total Billed: $3,185.19
This post is licensed under CC BY 4.0 by the author.