Formatting Numbers in Unity C# with Comma Separators: Exploring The FormattableString

Ketan Shukla
4 min readDec 6, 2023

--

Untangling the formatting string in Unity

Introduction:

In the realm of game development with Unity, managing and displaying large numbers is a common task. One particular challenge developers face is formatting these numbers with comma separators to enhance readability. This blog post delves into the intricacies of formatting numbers in Unity C# and explores why traditional methods like string.Format() and ToString() may not always yield the expected results, while FormattableString emerges as a reliable alternative.

The Common Approaches:

Let’s begin by examining some standard approaches to formatting numbers in Unity.

1. Using string.Format():

The string.Format() method is a powerful and flexible way to format strings in C#. However, when it comes to formatting numbers in Unity, this method might not produce the desired result. Unity uses a stripped-down version of the .NET runtime, and certain formatting features, especially those related to culture-specific formatting, might not behave as expected.

// Following will give the wrong result when used in Unity
string formattedNumber = string.Format("{0:#,##0}", number);

Workaround for the Issue:
To ensure consistent and expected formatting in Unity, we need to consider explicitly specifying the culture when formatting numbers. This can be achieved using the CultureInfo class from the System.Globalization namespace. By explicitly setting the desired culture, developers can have more control over how numbers are formatted.
Example with CultureInfo:

using System.Globalization; // add this namespace for CultureInfo

int number = 1513753;
// Explicitly specifying the culture (e.g., en-US)
string formattedNumber = string.Format(CultureInfo.InvariantCulture, "{0:N0}", number);

Output:

CultureInfo Gives Expected Result in Unity

2. Using ToString():

Another standard approach is using the ToString() method to format numbers. While this method is more straightforward, Unity's runtime might not handle it consistently. Unity's specific implementation may not support all the formatting options provided by the full .NET framework, and this can lead to unexpected results.

//Following would not work in Unity but would work in the regular .NET compiler
string formattedNumber = number.ToString("#,##0");
string formattedNumber2 = number.ToString("###,###,###,###,###,###");

While above methods work seamlessly in many C# applications, Unity introduces certain nuances due to its optimized runtime environment.

3. Using String interpolation using $

In the .NET framework, the N format specifier is designed to format a number according to the formatting conventions of the current culture, specifically using the comma as a thousands separator. For example, in the United States culture, the number 1513753 would be correctly formatted as 1,513,753 with the N0 format specifier.

However, Unity’s runtime environment introduces certain optimizations for game development. One notable optimization is in the area of culture-specific formatting. Unity tends to rely on a simplified or default culture setting, which can sometimes lead to unexpected results when formatting numbers.

string formattedNumber = number.ToString("#,##0");

Unity’s Implementation and Limitations:

Unity’s runtime environment is tailored for game development, and as such, it makes specific optimizations that may impact certain features of the full .NET framework. When it comes to formatting numbers with comma separators, Unity’s runtime may not consistently handle the formatting options provided by string.Format() and ToString().

The Solution: FormattableString:

Enter, a class within the System.Runtime.CompilerServices namespace. It offers a robust solution for creating culture-independent and strongly typed string formatting.

Example:

int number = 12345678;
FormattableString message = $"{number:N0}";
string formattedString = FormattableString.Invariant(message);

In this example, the N0 format specifier is used within the string interpolation to format the number with comma separators. The FormattableString.Invariant() method ensures culture-independent formatting, making it a reliable choice in Unity.

Practical Example with TextMeshPro:

To illustrate the effectiveness of FormattableString in Unity, let's consider a scenario using TextMeshPro:

using UnityEngine;
using TMPro;
using System;
using System.Globalization;
public class NumberDisplay : MonoBehaviour
{
public TMP_Text textMesh;

void Start()
{
int number = 1513753;

// Method 1: Using number.ToString("#,##0")
string op1 = number.ToString("#,##0");

// Method 2: Using string.Format("{0:#,##0}", number)
string op2 = string.Format("{0:#,##0}", number);

// Method 3: Using $"{number:N0}"
string op3 = $"{number:N0}";

// Method 4: Using FormattableString
FormattableString message = $"{number:N0}";
string op4 = FormattableString.Invariant(message);

// Method 5: Using TextMeshPro.SetText
string op5 = string.Format(CultureInfo.InvariantCulture, "{0:N0}", number);

// Displaying the results in TextMeshPro
textMesh.text = $"Result of <#8080ff>ToString(\"#,##0\")</color>\t {op1}\n" +
$"Result of <#80ff80>string.Format(\"{0:#,##0}\")</color>:\t {op2}\n" +
$"Result of <#ff8000>$\"{{number:N0}}\"</color>\t {op3}\n" +
$"Result of <#f0af80>FormattableString</color>\t {op4}\n" +
$"Result of <#ff0fff>string.Format(CultureInfo.InvariantCulture:</color>\n\t\t\t\t\t {op5}";
}
}

In this example, the TextMeshPro component displays the number 12345678 with comma separators, ensuring a visually appealing and easily readable representation. we can see this in the output screenshot below the first three entries give us the wrong result with the last two giving the expected one.

Output of various string formatting methods

Conclusion:

Formatting numbers in Unity C# with comma separators requires careful consideration of the runtime environment. While string.Format() and ToString() may not always produce the desired results due to Unity's optimizations, FormattableString emerges as a reliable alternative. By leveraging FormattableString, developers can ensure consistent and culture-independent formatting, enhancing the visual appeal of their games and applications. Understanding these nuances is crucial for creating robust and visually appealing user interfaces in Unity.

--

--

Ketan Shukla

Game Developer | Code Artisan | Tech Blogger | Crafting immersive game experiences. Explore my coding journey! #Cocos #Unity #Unreal www.codeinterstellar.com