27 KiB
Format alphanumeric data for presentation in C#
Introduction
Suppose you work for a sales and marketing department that sends thousands of personalized letters to the company's existing clients who are institutional investors. Your team's job is to promote new financial products to the customer. Each letter you send merges personalized information about the customer. The letter compares the returns of their current portfolios with projected returns using the newest products. How do you merge and format the data correctly?
From a high-level perspective, software developers are concerned with:
- data input, including data typed in by a user from a keyboard, using their mouse, a device, or by another software system via a network request.
- data processing, including decision logic, manipulating data, and performing calculations.
- data output, including presentation to an end user via a command-line message, a window, a web page, or saving the processed data into a file, and sending it to a network service.
To solve business problems in C#, you need to work with different types of data, such as strings and numbers. You also need to perform various operations on the data, such as calculations, comparisons, or conversions. In this module, you output string and numeric data in C# using various formatting options. You also create a receipt mockup and a personalized marketing message using data merging techniques.
Learning objectives
In this module, you will:
- Merge string templates with variables using composite formatting.
- Use various format specifiers to properly display percentages, currency, and numbers.
- Use padding methods to properly align string values.
Exercise - Investigate string formatting basics
In this unit, you learn methods to format strings for efficient display, especially for cases using multiple variables.
What is Composite Formatting?
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. Update your code in the editor as follows:
string first = "Hello";
string second = "World";
string result = string.Format("{0} {1}!", first, second);
Console.WriteLine(result);
If you run this code, you observe the following 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 variablefirst
. - The token
{1}
is replaced by the second argument after the string template, in other words, the value of the variablesecond
.
Note
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.
Update your code as follows:
string first = "Hello";
string second = "World";
Console.WriteLine("{1} {0}!", first, second);
Console.WriteLine("{0} {0} {0}!", first, second);
Save your code file, and then run your code. You should see the following output:
World Hello!
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:
string first = "Hello";
string second = "World";
Console.WriteLine($"{first} {second}!");
Console.WriteLine($"{second} {first}!");
Console.WriteLine($"{first} {first} {first}!");
Save your code file, and then run your code. You should see the following output:
Hello World!
World Hello!
Hello Hello Hello!
Note
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:
decimal price = 123.45m;
int discount = 50;
Console.WriteLine($"Price: {price:C} (Save {discount:C})");
If you executed this code on a computer that has its Windows display language set to "English (United States)", you observe the following 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
.
Note
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.
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 module, 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:
decimal measurement = 123456.78912m;
Console.WriteLine($"Measurement: {measurement:N} units");
If you're viewing this from the en-US
culture, you observe the following
output.
Measurement: 123,456.79 units
By default, the N
numeric format specifier displays only two digits after the
decimal point.
If you want to display more precision, you can do that by adding a number after
the specifier. The following code will display four digits after the decimal
point using the N4
specifier. Update your code as follows:
decimal measurement = 123456.78912m;
Console.WriteLine($"Measurement: {measurement:N4} units");
If you're viewing this from the en-US
culture, you observe the following
output.
Measurement: 123,456.7891 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:
decimal tax = .36785m;
Console.WriteLine($"Tax rate: {tax:P2}");
If you're viewing this from the en-US
culture, you observe the following
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.
Update your code as follows.
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);
If you're viewing this from the en-US
culture, you observe the following
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()
.
Note
You don't need to useString.Format()
with this string interpolation approach.
Update your code as follows.
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);
If you're viewing this unit from the en-US
culture, you observe the following
output.
You saved $7.56 off the regular $67.55 price. A discount of 11.19%!
Recap
Here are most important takeaways from this unit about string formatting:
- You can use composite formatting or string interpolation to format strings.
- With composite formatting, you use a string template containing one or
more replacement tokens in the form
{0}
. You also supply a list of arguments that are matched with the replacement tokens based on their order. Composite formatting works when usingstring.Format()
orConsole.WriteLine()
. - With string interpolation, you use a string template containing the
variable names you want replaced surrounded by curly braces. Use the
$
directive before the string template to indicate you want the string to be interpolated. - Format currency using a
:C
specifier. - Format numbers using a
:N
specifier. Control the precision (number of values after the decimal point) using a number after the:N
like{myNumber:N3}
. - Format percentages using the
:P
format specifier. - Formatting currency and numbers depend on the end user's culture, a five character code that includes the user's country/region and language (per the settings on their computer).
Exercise
Explore string interpolation
You need to create the code to print a receipt for the customer purchasing shares of an investment product. The shares are purchased automatically at the end of the year based on a series of payroll deductions, so the number of shares purchased usually contains a decimal amount. To print the receipt, you would likely need to combine data of different types, including fractional values, currency, and percentages in precise ways.
Display the invoice number using string interpolation
Update your code in the editor as follows:
int invoiceNumber = 1201;
decimal productShares = 25.4568m;
decimal subtotal = 2750.00m;
decimal taxPercentage = .15825m;
decimal total = 3185.19m;
Console.WriteLine($"Invoice Number: {invoiceNumber}");
The Program.cs file must be saved before building or running the code.
At the Terminal command prompt, to run your code, type dotnet run
and then
press Enter.
You should see the following output:
Invoice Number: 1201
Note
You may see several warnings such aswarning CS0219: The variable 'productShares' is assigned but its value is never used
for all the variables that were defined but not yet used in the code.
Display the product shares with one thousandth of a share (0.001) precision
Since you bill the customers using fractions of shares even though the precision is one ten thousandth (0.0001), you'll only display three digits after the decimal point.
Add the following code below the code you typed previously:
Console.WriteLine($" Shares: {productShares:N3} Product");
Save your code file, and then run your code.
When you run the code, you should see the following output:
Invoice Number: 1201
Shares: 25.457 Product
Display the subtotal that you charge the customer formatted as currency
Add the following code below the code you typed in steps 1 and 2:
Console.WriteLine($" Sub Total: {subtotal:C}");
When you run the code, you should see the following output:
Invoice Number: 1201
Shares: 25.457 Product
Sub Total: $2,750.00
Note
The sample shows the "$" but you may see a different regional currency symbol.
Display the tax charged on the sale formatted as a percentage
Add the following code below the code you typed in steps 1 through 3:
Console.WriteLine($" Tax: {taxPercentage:P2}");
When you run the code, you should see the following output:
Invoice Number: 1201
Shares: 25.457 Product
Sub Total: $2,750.00
Tax: 15.83%
Finalize the receipt with the total amount due formatted as currency
Add the following code below the code you typed in steps 1 through 4:
Console.WriteLine($" Total Billed: {total:C}");
The entire code for the exercise should match as follows:
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}");
When you run the code, you should see the following output:
Invoice Number: 1201
Shares: 25.457 Product
Sub Total: $2,750.00
Tax: 15.83%
Total Billed: $3,185.19
Exercise
Discover padding and alignment
The string.Format()
method is used to perform composite formatting such as in
the example:
string first = "Hello";
string second = "World";
string result = string.Format("{0} {1}!", first, second);
Console.WriteLine(result);
It may have seemed a bit strange that a keyword that represents a data type has
methods you can call in the same way that you call methods on the Console
class. The fact is that there are many similar methods on the string
data type
and any literal string or variable of type string.
Here's a brief list of categories of these built-in methods so you can get an idea of what's possible.
- Methods that add blank spaces for formatting purposes (
PadLeft()
,PadRight()
) - Methods that compare two strings or facilitate comparison (
Trim()
,TrimStart()
,TrimEnd()
,GetHashcode()
, theLength
property) - Methods that help you determine what's inside of a string, or even retrieve
just a part of the string (
Contains()
,StartsWith()
,EndsWith()
,Substring()
) - Methods that change the content of the string by replacing, inserting, or
removing parts (
Replace()
,Insert()
,Remove()
) - Methods that turn a string into an array of strings or characters (
Split()
,ToCharArray()
)
Formatting strings by adding whitespace before or after
The PadLeft()
method adds blank spaces to the left-hand side of the string so
that the total number of characters equals the argument you send it. In this
case, you want the total length of the string to be 12 characters.
Update your code in the editor as follows:
string input = "Pad this";
Console.WriteLine(input.PadLeft(12));
At the Terminal command prompt, to run your code, type dotnet run
and then
press Enter.
When you run the code, you observe four characters prefixed to the left of the string bring the length to 12 characters long.
Pad this
To add space or characters to the right side of your string, use the
PadRight()
method instead. 1. Update your code in the editor as follows:
Console.WriteLine(input.PadRight(12));
Save your code file, and then run your code. You won't observe any characters added to the end of the string, but they're there.
What is an overloaded method?
In C#, an overloaded method is another version of a method with different or
extra arguments that modify the functionality of the method slightly, as is the
case with the overloaded version of the PadLeft()
method.
You can also call a second overloaded version of the method and pass in whatever character you want to use instead of a space. In this case, you fill the extra space with the dash character.
Update your code in the editor as follows:
Console.WriteLine(input.PadLeft(12, '-'));
Console.WriteLine(input.PadRight(12, '-'));
Save your code file, and then run your code. You should see four dashes prefixing the left of the string that is 12 characters long.
----Pad this
Pad this----
Now, apply this newfound knowledge to another real world scenario.
Working with padded strings
Suppose you work for a payment processing company that still supports legacy mainframe systems. Often, those systems require data to be input in specific columns. For example, store the Payment ID in columns 1 through 6, the payee's name in columns 7 through 30, and the Payment Amount in columns 31 through 40. Also, importantly, the Payment Amount is right-aligned.
You're asked to build an application that will convert data in the relational database management system to the legacy file format. To ensure that the integration works correctly, the first step is to confirm the file format by giving the legacy system maintainers a sample of the output. Later, you build on this work to send hundreds or thousands of payments to be processed via an ASCII text file.
Add the Payment ID to the output
To get started, print the Payment ID in the first six columns. You pick some random payment data that should be adequate for the purposes.
Update your code in the editor as follows:
string paymentId = "769C";
var formattedLine = paymentId.PadRight(6);
Console.WriteLine(formattedLine);
Reuse the formattedLine
variable to build the output string.
Save your code file, and then run your code. You should see the following output:
769C
There are two blank spaces to the right that not visible. You'll confirm that they exist in the next step.
Add the payee name to the output
Next, you add a fictitious Payee Name, padding it appropriately.
Update your code as follows:
string paymentId = "769C";
string payeeName = "Mr. Stephen Ortega";
var formattedLine = paymentId.PadRight(6);
formattedLine += payeeName.PadRight(24);
Console.WriteLine(formattedLine);
The +=
operator performs a string concatenation, taking the previous value of
the variable formattedLine
and adding the new value to it. It's a shortened
equivalent the following code example:
formattedLine = formattedLine + payeeName.PadRight(24);
Save your code file, and then run your code. You should see the following output:
769C Mr. Stephen Ortega
Again, there are quite a few blank spaces after the Payee's Name. Also, there are two blank spaces after the Payment ID from Step 1.
Add the payment amount to the output
Next, add a fictitious Payment Amount and make sure to use PadLeft()
to right
-align the output.
Update your code as follows:
string paymentId = "769C";
string payeeName = "Mr. Stephen Ortega";
string paymentAmount = "$5,000.00";
var formattedLine = paymentId.PadRight(6);
formattedLine += payeeName.PadRight(24);
formattedLine += paymentAmount.PadLeft(10);
Console.WriteLine(formattedLine);
Save your code file, and then run your code. You should see the following output:
769C Mr. Stephen Ortega $5,000.00
This output is pretty close to what you understood the legacy system maintainers were looking for.
Add a line of numbers above the output to more easily confirm the result
Since it's difficult to count the exact columns where each data element appears, you add a line directly above the output that helps you count the columns.
Console.WriteLine("1234567890123456789012345678901234567890");
Update your code in the Visual Studio Code Editor as follows:
string paymentId = "769C";
string payeeName = "Mr. Stephen Ortega";
string paymentAmount = "$5,000.00";
var formattedLine = paymentId.PadRight(6);
formattedLine += payeeName.PadRight(24);
formattedLine += paymentAmount.PadLeft(10);
Console.WriteLine("1234567890123456789012345678901234567890");
Console.WriteLine(formattedLine);
Save your code file, and then run your code. You should see the following output, that you can send off to the maintainers of the legacy system to confirm the new integration works correctly:
1234567890123456789012345678901234567890
769C Mr. Stephen Ortega $5,000.00
Success!
Recap
There's a few important takeaways from this unit.
- The
string
data type, literal strings, and variables of type string each implement many helper methods to format, modify, and perform other operations on strings. - The
PadLeft()
andPadRight()
methods add white space (or optionally, another character) to the total length of a string. - Use
PadLeft()
to right-align a string. - Some methods are overloaded, meaning they have multiple versions of the method with different arguments that affect their functionality.
- The
+=
operator concatenates a new string on the right to the existing string on the left.
Exercise
Complete a challenge to apply string interpolation to a form letter
For the sales and marketing company's newest investment products, you send thousands of personalized letters to the company's existing clients. Your job is to write C# code to merge personalized information about the customer. The letter contains information like their existing portfolio and compares their current returns to projected returns if they were to invest in using the new products.
The writers have decided on the following example marketing message. Here's the desired output (using fictitious customer account data).
Dear Ms. Barros,
As a customer of our Magic Yield offering we are excited to tell you about a new financial product that would dramatically increase your return.
Currently, you own 2,975,000.00 shares at a return of 12.75%.
Our new product, Glorious Future offers a return of 13.13%. Given your current volume, your potential profit would be ¤63,000,000.00.
Here's a quick comparison:
Magic Yield 12.75% $55,000,000.00
Glorious Future 13.13% $63,000,000.00
Use your new found knowledge of string formatting to build an application that can merge and format the appropriate content given the previous example output. Pay particular attention to the white space and make sure you accurately represent this exact format using C#.
Add the following code to get the data for the challenge:
string customerName = "Ms. Barros";
string currentProduct = "Magic Yield";
int currentShares = 2975000;
decimal currentReturn = 0.1275m;
decimal currentProfit = 55000000.0m;
string newProduct = "Glorious Future";
decimal newReturn = 0.13125m;
decimal newProfit = 63000000.0m;
// Your logic here
Console.WriteLine("Here's a quick comparison:\n");
string comparisonMessage = "";
// Your logic here
Console.WriteLine(comparisonMessage);
Use the code editor to generate the message while using the given variables and code.
Ensure your code outputs the following message:
Dear Ms. Barros,
As a customer of our Magic Yield offering we are excited to tell you about a new financial product that would dramatically increase your return.
Currently, you own 2,975,000.00 shares at a return of 12.75%.
Our new product, Glorious Future offers a return of 13.13%. Given your current volume, your potential profit would be $63,000,000.00.
Here's a quick comparison:
Magic Yield 12.75% $55,000,000.00
Glorious Future 13.13% $63,000,000.00
Good luck!
Whether you get stuck and need to peek at the solution or you finish successfully, continue on to view a solution to this challenge.
Summary
Your company needed to create a personalized marketing message to promote a new financial product to your customers. Using C#, you were able to write code that combined string and numeric data about your current customers.
You exercised different techniques for merging a string template with variables using composite formatting and string interpolation. The various specifiers allow you to properly format large numbers, currency, and percentages. The built-in methods on variables of type string allowed you to add padding to left and right align data.
Imagine how much extra work is required if you didn't have a wealth of string and number formatting tools and techniques available to you in C#. You would likely attempt to use string concatenation everywhere, possibly making it difficult to maintain or update.
Techniques and tools for formatting strings and numeric data has a wide array of applications. For example, you can use these techniques to present data for display on screen and format data to transfer between disparate systems.