Strings
Keywordsstring, $"...", @"...", StringBuilder
NamespaceSystem, System.Text
In UnityUI text, Debug.Log, save keys, dialogue

Strings & Formatting

A string is text. This page covers building strings for UI and logs (interpolation and number formatting), common string methods, and how to avoid the performance trap of rebuilding text every frame.

String interpolation

Put $ before the quotes and write values inside { }. It's the clearest way to build text.

int coins = 42;
float time = 83.456f;

string a = "Coins: " + coins + " Time: " + time; // old way: concatenation
string b = $"Coins: {coins} Time: {time}";        // interpolation: same result, easier to read

Debug.Log($"{name} is at {transform.position}");

Formatting numbers

Add :format after the value inside the braces:

CodeResult for 1234.5678Use for
$"{x:F0}"1235Whole numbers (rounded)
$"{x:F2}"1234.572 decimal places
$"{x:N0}"1,235Thousands separators (scores)
$"{x:0000}"1235Pad with zeros: 7 → 0007
$"{0.75f:P0}"75%Percentages
$"{x,8}""  1234.5678"Right-align in 8 characters

Separators and decimal points follow the player's system language (e.g. "1.234,57" in German) unless you pass CultureInfo.InvariantCulture.

A timer display

float seconds = 83.456f;
int m = (int)(seconds / 60f);
float s = seconds % 60f;
timerText.text = $"{m:00}:{s:00.00}"; // "01:23.46"

// Or with TimeSpan
var t = System.TimeSpan.FromSeconds(seconds);
timerText.text = t.ToString(@"mm\:ss"); // "01:23"

Useful string methods

MethodExampleResult
Length"Hello".Length5
ToUpper() / ToLower()"Hi".ToUpper()"HI"
Contains(s)"Goblin King".Contains("King")true
StartsWith / EndsWithname.StartsWith("Enemy_")true/false
Replace(a, b)"(Clone)".Replace("(Clone)", "")""
Split(c)"a,b,c".Split(',')["a","b","c"]
Trim()" hi ".Trim()"hi"
Substring(start, len)"Unity".Substring(0, 3)"Uni"
string.IsNullOrEmpty(s)string.IsNullOrEmpty(input)true if null or ""
string.Join(sep, items)string.Join(", ", names)"Ana, Ben"
string.Equals(a, b, StringComparison.OrdinalIgnoreCase)compare ignoring casetrue/false

Special characters

string line  = "First line\nSecond line";   // \n = new line
string quote = "She said \"hi\"";           // \" = a quote inside the string
string path  = @"C:\Games\Save";            // @ = backslashes are literal (verbatim)
string brace = $"Use {{braces}} like this";  // {{ }} = literal braces in interpolation

StringBuilder: building big strings

Strings can't be changed. Every + makes a new string and throws the old one away. For building long text in a loop, use StringBuilder, which grows one buffer instead.

Writing a letter in pen. With plain strings, fixing one word means rewriting the whole letter on a fresh sheet and throwing the old one away. A StringBuilder is a notepad in pencil: you keep adding and editing the same page, and only copy it out neatly (ToString()) at the end.

using System.Text;

private readonly StringBuilder sb = new StringBuilder(256); // reuse this one

void ShowInventory(List<Item> items)
{
    sb.Clear();
    sb.AppendLine("Inventory:");
    foreach (Item item in items)
    {
        sb.Append("- ").Append(item.displayName).Append(" x").Append(item.count).AppendLine();
    }
    inventoryText.text = sb.ToString();
}

What happens at runtime

  1. Each new string is a heap allocation. $"Score: {score}" in Update creates garbage every frame, even if the score didn't change.
  2. Setting a TextMeshPro text property also makes it rebuild its mesh, which costs time.
  3. So: only update text when the value actually changes.
private int shownScore = -1;

void Update()
{
    if (score == shownScore) return;      // nothing changed: no new string, no mesh rebuild
    shownScore = score;
    scoreText.text = $"Score: {score:N0}";
}
// Even better: update from a "score changed" event instead of polling in Update.

Common Mistakes

See also