帳票に金額を出す時、"" + kingaku + " 円" みたいに + で連結して組んでませんか?
これ、桁が増えると読みにくい。カンマ区切りにしようとすると急に面倒になる。
金曜の夕方に「この金額、3桁区切りにして」って言われて、ToString("#,0") ってどこに挟むんやっけ??と一瞬固まる。あの感じ、経験ないですか?
どうも、ヒロポンです。
今回は C# の文字列フォーマットを、文字列補間・string.Format・複合書式指定の3つで使い分ける話。帳票の金額やログの整形を、+ 連結から卒業してきれいに書きたい業務SE向けです。コピペで動く形で並べます。
先に地雷を1個だけ。{0:C}(通貨書式)は実行環境のカルチャで通貨記号が変わります。開発機(日本語)だと ¥ だけど、本番サーバーが英語設定だと $ が出る。帳票で $ が刷られたら事故。これは後で詳しく書きます。
💡
+/Concat/StringBuilder/ 補間 の速度を比べた話は別記事 C# 文字列結合のパフォーマンス完全比較 にあります。あっちは速度の軸、今回は書式と可読性の軸。合わせて読むと文字列まわりが一通り埋まります。
結論: 3つは役割が違う。補間=その場、Format=テンプレ外出し、複合書式=整形記法
先に answer。この3つは競合するものじゃなくて、役割分担です。
- 文字列補間
$""→ 変数がその場にある時の第一候補。$"{name} さん: {amount:N0} 円" string.Format→ テンプレート文字列を外に出したい / 定数化したい時- 複合書式指定
{0:N0}→ 数値や日付を整形する記法そのもの。補間でも Format でも同じように使える
つまり「補間か Format か」はテンプレートをその場に書くか外に出すかの違い。{0:N0} みたいな整形記法はどっちでも共通です。
ここを分けて捉えると、迷わなくなる。

なぜ + 連結で金額を組むと辛いのか
+ 連結そのものは動きます。ただ、書式が絡んだ瞬間に急に読みにくくなる。
たとえば「1234567 を 1,234,567 円 と出す」だけで、+ 連結と補間を並べると差がハッキリ出ます。

+ だと ToString("#,0") が連結の途中に挟まる。どこが変数でどこが固定文字か、一目で分からない。
これが5項目、10項目と増えると帳票コードが地獄になります。
補間なら同じ結果で、圧倒的に読みやすい。これが「書式は補間 or Format で書く」の一番の理由です。
最短対処: コピペで動く3つの書き方
① 文字列補間 $"" — 変数がその場にある時の第一候補
$ を頭に付けて、{変数} で埋め込む。書式は {変数:書式指定子} で足す。
string name = "山田";
decimal kingaku = 1234567m;
DateTime hizuke = new DateTime(2026, 7, 5);
string line = $"{name} さん / 金額 {kingaku:N0} 円 / {hizuke:yyyy/MM/dd}";
// → 山田 さん / 金額 1,234,567 円 / 2026/07/05
実行結果:

変数がスコープにあるなら、まずこれ。1行の帳票行やログメッセージはだいたい補間で済みます。いい感じに読めるはず!!
② string.Format — テンプレートを外に出す・ログの定数化
テンプレート文字列を定数やリソースに外出ししたい時は string.Format。{0} {1} の番号で差し込みます。
// 書式テンプレを定数にできる(補間だとこれができない)
const string LogFormat = "[{0:yyyy/MM/dd HH:mm:ss}] {1} 件処理 / 金額 {2:N0} 円";
string log = string.Format(LogFormat, DateTime.Now, count, total);
ログの書式を1箇所で管理したい、多言語のリソースから読みたい。そういう時に効きます。
補間は「その場」に強く、Format は「外出し」に強い。こんな感じでいい感じの住み分けです。
③ 複合書式指定 {0:N0} — 数値・日付を整形する記法
{0:N0} の : 以降が書式指定子。これは補間でも Format でも共通です。
よく使うやつを並べます。

{0,10:N0} のように桁揃え(alignment)と書式を同時に指定もできる。帳票の縦位置がこんな感じで揃うので便利です。
日付の書式指定子はバリエーションが多い。そこだけ深掘りしたい人は C# DateTime のフォーマット完全早見表 にまとめてます。
ハマりポイント: 知らないと本番でズレる
ハマり1: {0:C} の通貨記号は実行環境のカルチャで変わる
これが一番の地雷。{0:C}(通貨書式)は、実行環境の CurrentCulture に依存します。
decimal price = 1000m;
string s = $"{price:C}";
// 開発機(ja-JP): ¥1,000 ← .NET が返すのは全角の ¥ (U+FFE5)
// 本番サーバー(en-US): $1,000.00
// InvariantCulture: ¤1,000.00 ← ¤ は汎用通貨記号
開発機(日本語)では円記号が出るのに、本番の Linux サーバーが en-US や InvariantCulture だと $ や ¤ になる。
帳票に「$1,000.00」が刷られて発覚、みたいな事故が起きます。
なんで本番だけ $ なん??ってなるやつ。しかも開発機では再現しない。血の気が引きます。
(細かい話ですが、.NET が ja-JP で返す円記号は半角 ¥ ではなく全角の ¥ です。表示幅を気にする帳票だとここも効いてきます。)
回避は、カルチャを明示的に渡して固定する。
using System.Globalization;
var jp = CultureInfo.GetCultureInfo("ja-JP");
// string.Format はカルチャを第1引数で渡せる
string s1 = string.Format(jp, "{0:C}", price); // 環境に関わらず 常に ¥1,000
// 補間は FormattableString 経由で固定する
string s2 = ((FormattableString)$"{price:C}").ToString(jp);
実行結果(同じ 1000 が ja-JP / en-US / InvariantCulture で変わる・固定後は常に円記号):

「金額を扱う帳票では {0:C} を裸で使わない。カルチャを固定する」。これだけ覚えておけば本番ズレは防げます。
ハマり2: {0:D} は整数型専用(decimal に使うと FormatException)
カンマ区切りにしたくて {0:D} を使う人がいるけど、これは罠。D(10進数)書式は 整数型(int / long 等)専用です。
int seq = 42;
string ok = $"{seq:D5}"; // 00042(ゼロ埋め・OK)
decimal kingaku = 1234.5m;
string ng = $"{kingaku:D}"; // ← FormatException! D は整数型だけ
decimal や double に D を使うと実行時に落ちる。
カンマ区切りがしたいなら N0 / N2、ゼロ埋めがしたい整数なら D5、と使い分けます。
ん? D でカンマ入るんちゃうの??って混同しがちなんで注意。
ハマり3: 補間で中括弧 { を出すには {{ とエスケープ
補間の中で { } をそのまま書くと、変数の開始と解釈されてエラー。リテラルの中括弧を出したい時は {{ }} と2つ重ねます。
string json = $"{{ \"id\": {id}, \"name\": \"{name}\" }}";
// → { "id": 1, "name": "山田" }
補間で JSON っぽい文字列を組む時に踏むやつ。{{ で {、}} で } になる。
地味だけど、知らないと詰まります。
現場メモ: 帳票コードが読みやすくなると保守がラク
ここからは現場メモ。
俺が業務系で帳票を触ってた頃、金額と日付が並ぶ明細行が + 連結でびっしり書かれてました。1行直すのに毎回目を凝らして、どこが変数か探すところから始まる。
これを補間 + N0 / yyyy/MM/dd に置き換えたら、明細1行が「何を出してるか」パッと読めるようになった。
書式指定子を覚えるコストはある。けど、一度入れればレビューも修正も速くなる。
派手な最適化じゃない。ただ帳票って直す頻度が高いんで、読みやすさがじわじわ効いてくる。書式まわりは「速度より可読性」で選んでいいと思ってます。カルチャ固定だけ忘れずに!!
まとめ
C# の文字列フォーマット、使い分けはこれだけ。
- 補間
$""→ 変数がその場にある1行の組み立て。第一候補 string.Format→ テンプレを定数・リソースに外出しする時- 複合書式指定 →
N0(カンマ)/yyyy/MM/dd(日付)/D5(ゼロ埋め)。補間でも Format でも共通 - カルチャ注意 →
{0:C}は環境依存。金額帳票では CultureInfo を固定する
+ 連結から補間に寄せると、帳票コードが一気に読みやすくなります。
書式指定子を一度押さえておくと、金額も日付もパーセントも同じ記法で整形できる。いい感じに現場でずっと使い回せます。
よくある質問
補間って パフォーマンス的に + 連結より遅くない?
1行の組み立てなら気にする差は出ません。補間は内部的に string.Format 相当になりますが、帳票1行やログ1件のレベルでは可読性のメリットの方が大きい。大量ループでの連結が問題になるケースは 文字列結合のパフォーマンス比較 を見てください。そこは StringBuilder の領域です。
書式指定子ってどこかに一覧ある? 全部覚えるの?
全部は覚えなくていいです。実務で使うのは N0 / N2 / C / P / 日付系 / D5(ゼロ埋め)くらい。この記事の早見表をブックマークして、必要な時に引くので十分です。よく使う数個が手に馴染めば回ります。
string.Format と補間、チームでどっち使うか揃えるべき?
「その場の組み立ては補間、外出しテンプレは Format」で揃えるのがおすすめです。どちらか一方に統一するより、役割で分けた方が自然で、レビューでも揉めません。ログの書式定数だけ Format、あとは補間、くらいの緩いルールが現場では回りやすいです。
金額の負数をカッコ表記にしたい(会計表記)んだけど?
セミコロンで「正;負;ゼロ」の3セクションに分けて書式を指定できます。ただしこのセクション書式の中では N0 などの標準書式指定子は効かない(N がただの文字扱いになって (N1234) みたいに出る)ので、カスタム書式指定子で書きます。負数をカッコで囲むなら {0:#,##0;(#,##0)} で -1234 が (1,234) になります。#,##0 がカンマ区切りのカスタム指定子です。凝った帳票フォーマットは、このセクション区切り + カスタム指定子で表現できると覚えておくと便利です。
次に読むべき記事





以上!
帳票の $ 事故、経験ある人けっこういると思うんで、どんどんシェア待ってるぜ!!
執筆者
バイブス父さん — 業務 SE 7 年(正社員 2 / フリーランス 5)。現職は SEO 直轄部の AI アドバイザー兼 PL、副業で中小 SIer の CTO。SIer 正社員から独立し、複数のフリーランスエージェント経由で現場を渡り歩いた経験ベースで「業務 SE 視点」の技術 + キャリア記事を書いています。
🐦 X: @hiro_progra0524(日々の現場メモ更新中)
📝 About Me で経歴詳細を見る




