C#を使用したプログラミングにおいて、数値や日付を特定の形式で表示したり、複数の変数を一つの文字列にまとめたりする操作は非常に頻繁に行われます。
その際、中心的な役割を果たすのがString.Formatメソッドです。
近年では文字列補完($記号を用いた記述)が主流になりつつありますが、動的な書式設定や多言語対応、複雑なテンプレート管理においては、依然としてString.Formatの知識が欠かせません。
この記事では、初心者から中級者までを対象に、基本的な使い方から高度な書式指定まで徹底的に解説します。
String.Formatの基本概念と構文
String.Formatは、文字列内の特定の位置に、指定したオブジェクトの値を挿入するためのメソッドです。
最大の特徴は、単に値を埋め込むだけでなく、表示形式(書式)を詳細にコントロールできる点にあります。

基本的な構文とプレースホルダー
String.Formatの第一引数には、複合書式指定文字列と呼ばれるテンプレートを渡します。
この文字列の中にある {0} や {1} といった記述をプレースホルダーと呼びます。
using System;
public class Program
{
public static void Main()
{
string name = "田中";
int age = 25;
// {0}にname、{1}にageが順番に埋め込まれる
string message = String.Format("こんにちは、{0}さん。年齢は{1}歳ですね。", name, age);
Console.WriteLine(message);
}
}
こんにちは、田中さん。年齢は25歳ですね。
プレースホルダー内の数字は、第二引数以降に渡したオブジェクトのインデックス(0から始まる番号)に対応しています。
インデックスを間違えると、意図しない場所に値が表示されたり、System.FormatExceptionが発生したりするため注意が必要です。
また、同じインデックスを複数回使用することも可能です。
プレースホルダーの高度な構造
プレースホルダーは、単純なインデックス指定だけでなく、表示幅や書式を指定するための拡張構文を持っています。
基本構造は以下の通りです。
{index[,alignment][:formatString]}
- index:挿入するオブジェクトの番号。
- alignment:オプション。表示幅を指定し、右寄せ・左寄せを制御します。
- formatString:オプション。数値や日付の具体的な書式を指定します。
数値の書式設定
数値を表示する際、通貨記号を付けたり、小数点以下の桁数を固定したり、あるいは3桁ごとにカンマを入れたりといった処理が必要です。
これらはformatStringの部分に特定の書式指定子を記述することで実現できます。

標準的な数値書式指定子
よく使われる数値書式指定子を以下の表にまとめました。
| 指定子 | 名前 | 説明 | 例(1234.5の場合) |
|---|---|---|---|
| C | 通貨 | ローカルの通貨記号(¥など)を付与 | ¥1,235 |
| D | 10進数 | 整数のみ。0埋め(パディング)に利用 | 001234(D6指定時) |
| F | 固定小数点 | 小数点以下の桁数を固定 | 1234.50(F2指定時) |
| N | 数値 | 3桁区切りのカンマと小数点 | 1,234.50 |
| X | 16進数 | 数値を16進数文字列に変換 | 4D2 |
using System;
public class Program
{
public static void Main()
{
double price = 1234.567;
int count = 42;
// 通貨形式(C)、小数点第2位までの固定小数点(F2)
string s1 = String.Format("価格: {0:C}, 指数: {0:F2}", price);
// 16進数(X)
string s2 = String.Format("16進数表示: 0x{0:X}", count);
Console.WriteLine(s1);
Console.WriteLine(s2);
}
}
価格: ¥1,235, 指数: 1234.57
16進数表示: 0x2A
C(通貨)やN(数値)を使用すると、既定では実行環境の地域設定(カルチャ)に基づいて整形されます。
また、指定子の直後に数字を記述することで(例:F3)、精度(小数点以下の桁数など)を細かく制御できます。
カスタム数値書式(#と0の使い分け)
標準の指定子では対応できない複雑な形式には、#や0を用いたカスタム書式を使用します。
- 0:ゼロプレースホルダー。値がない場合は0を表示します(強制的な0埋め)。
- #:桁プレースホルダー。値がある場合のみ表示します。
using System;
public class Program
{
public static void Main()
{
double value = 1.2;
// 0埋めを強制する場合
string s1 = String.Format("{0:00.00}", value); // 01.20
// 値があるときだけ表示する場合
string s2 = String.Format("{0:##.##}", value); // 1.2
Console.WriteLine("s1: " + s1);
Console.WriteLine("s2: " + s2);
}
}
s1: 01.20
s2: 1.2
日付と時刻の書式設定
DateTimeオブジェクトを文字列に変換する場合も、String.Formatは威力を発揮します。
システムログの記録や画面表示など、用途に応じて柔軟な形式変換が求められます。

標準の日時指定子
日付にも「短い形式」や「長い形式」などのプリセットが用意されています。
- d:短い日付(例:2026/01/16)
- D:長い日付(例:2026年1月16日金曜日)
- t:短い時刻(例:15:30)
- T:長い時刻(例:15:30:45)
カスタム日時指定子
実務で最も多く使われるのは、任意のフォーマットを構築するカスタム指定子です。
using System;
public class Program
{
public static void Main()
{
DateTime now = new DateTime(2026, 1, 16, 15, 30, 45);
// yyyy:年(4桁), MM:月(2桁), dd:日(2桁), HH:時(24h), mm:分, ss:秒
string formatted = String.Format("現在は {0:yyyy年MM月dd日 HH時mm分ss秒} です。", now);
Console.WriteLine(formatted);
}
}
現在は 2026年01月16日 15時30分45秒 です。
ここで注意すべき点は、月の「MM」は大文字であり、分の「mm」は小文字であることです。
これを間違えると、月を表示したい場所に分が表示されてしまうといったミスに繋がります。
アライメント(配置)とパディング
表形式でデータを出力したい場合など、文字列の幅を揃える必要があるときにアライメント(配置)機能を使用します。

数値による幅の指定
プレースホルダーの中で、インデックスの後にカンマ区切りで数値を指定します。
- 正の整数:右寄せ(指定した幅に満たない場合は左側に半角スペースが挿入される)。
- 負の整数:左寄せ(指定した幅に満たない場合は右側に半角スペースが挿入される)。
using System;
public class Program
{
public static void Main()
{
string header = String.Format("{0,-10} | {1,10}", "アイテム名", "単価");
string item1 = String.Format("{0,-10} | {1,10:C}", "リンゴ", 150);
string item2 = String.Format("{0,-10} | {1,10:C}", "メロン", 3000);
Console.WriteLine(header);
Console.WriteLine(new string('-', 23));
Console.WriteLine(item1);
Console.WriteLine(item2);
}
}
アイテム名 | 単価
-----------------------
リンゴ | ¥150
メロン | ¥3,000
上記のコードでは、{0,-10}によって「10文字分の幅で左寄せ」を実現し、{1,10:C}によって「10文字分の幅で右寄せ、かつ通貨形式」を同時に指定しています。
このようにアライメントと書式指定子は組み合わせて使用することが可能です。
特殊文字の扱い(エスケープ)
String.Formatにおいて、波括弧 { } は特別な意味を持ちます。
もし文字列としてそのまま波括弧を表示したい場合は、二重に記述することでエスケープする必要があります。
using System;
public class Program
{
public static void Main()
{
int val = 100;
// {{ と }} で囲むことで、結果として単一の { } が表示される
string s = String.Format("値は {{ {0} }} です。", val);
Console.WriteLine(s);
}
}
値は { 100 } です。
これを忘れると、コンパイラが「新しいプレースホルダーの開始」だと誤認し、エラーが発生します。
文字列補完(Interpolated Strings)との使い分け
C# 6.0以降では、文字列補完($記号)という機能が登場しました。
これはString.Formatをより簡潔に書けるようにしたもので、現在の開発現場ではこちらが主流です。
// String.Formatの場合
string s1 = String.Format("名前: {0}, 年齢: {1}", name, age);
// 文字列補完の場合(より直感的)
string s2 = $"名前: {name}, 年齢: {age}";
しかし、String.Formatが完全に不要になったわけではありません。
以下のようなケースでは、依然としてString.Formatが適しています。
- 外部設定ファイルからの読み込み
データベースやリソースファイルに「こんにちは、{0}さん」というテンプレートを保存しておき、実行時に値を埋め込む場合。
- 動的な書式選択
条件によって書式文字列自体を切り替えたい場合。
- 古いコードの保守
既存のプロジェクトとの一貫性を保つ必要がある場合。
文字列補完も内部的にはString.Formatと同様の仕組みで動作しているため、本記事で解説した数値や日付の書式指定(:Cや:yyyyなど)は、文字列補完の中でも全く同じように使用できます。
パフォーマンスに関する考慮事項
String.Formatをループの中で数万回呼び出すような処理を行う場合、パフォーマンスに注意が必要です。
このメソッドは内部で文字列の解析やボクシング(値型をオブジェクト型に変換する処理)を行うため、単純な文字列結合よりもオーバーヘッドが大きくなります。

大量の文字列を組み立てる際は、StringBuilder.AppendFormatメソッドの使用を検討してください。
これにより、新しい文字列オブジェクトが大量に生成されるのを防ぎ、メモリ効率を向上させることができます。
まとめ
String.Formatは、C#における文字列操作の基本でありながら、非常に奥の深い機能です。
インデックスによる引数の指定から始まり、数値・日付の書式設定、アライメントによるレイアウト調整まで、その機能は多岐にわたります。
現代のC#開発においては、ソースコードの可読性を高めるために文字列補完($)を優先的に使いつつ、テンプレートを外部化する場合や、より動的な処理が必要な場合にString.Formatを選択するという使い分けがベストプラクティスと言えます。
本記事で紹介した各種指定子(C, N, yyyyなど)をマスターすることで、ユーザーにとって読みやすく、プロフェッショナルな外観を持つアプリケーションを構築できるようになるでしょう。
まずは基本のプレースホルダーから試し、徐々に複雑なカスタム書式に挑戦してみてください。
