動くコード図鑑技術記事現場の渡り方キャリア論すべての記事About
技術記事

C# の文字列補間 ($””) と string.Format と複合書式指定の使い分け3パターン(帳票・ログ整形)

バイブス父さん
現役の業務SE
2026年7月9日12 min read
C# の文字列補間 ($””) と string.Format と複合書式指定の使い分け3パターン(帳票・ログ整形)

帳票に金額を出す時、"" + 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} みたいな整形記法はどっちでも共通です。

ここを分けて捉えると、迷わなくなる。

C# の文字列補間・string.Format・複合書式指定の3つを、書き方・向いている場面・テンプレート再利用の可否で比較した表

なぜ + 連結で金額を組むと辛いのか

+ 連結そのものは動きます。ただ、書式が絡んだ瞬間に急に読みにくくなる

たとえば「1234567 を 1,234,567 円 と出す」だけで、+ 連結と補間を並べると差がハッキリ出ます。

金額を + 連結で ToString 書式を挟んで組む書き方と、文字列補間で N0 書式を使う書き方の before/after

+ だと 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

実行結果:

文字列補間で N0 のカンマ区切りと yyyy/MM/dd の日付整形を組み合わせた実行結果

変数がスコープにあるなら、まずこれ。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 でも共通です。

よく使うやつを並べます。

C# の複合書式指定子 N0 / N2 / C / P / yyyy-MM-dd / D5 / 右寄せの入力例と出力例をまとめた早見表

{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-USInvariantCulture だと $¤ になる。

帳票に「$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 で変わる・固定後は常に円記号):

decimal 1000 を {0:C} で整形すると ja-JP は全角円記号・en-US はドル・InvariantCulture は汎用通貨記号になり、CultureInfo を明示すると環境に関わらず固定される実機結果

「金額を扱う帳票では {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 は整数型だけ

decimaldoubleD を使うと実行時に落ちる。

カンマ区切りがしたいなら 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 で経歴詳細を見る


この記事のコードと手順は ぜんぶ動作検証済み。 安心して現場で試してくれ。
バイブス父さん

現役の業務SE。C# / SQL Server 保守の現場から、コードも人もキャリアも全部書く。 実体験ベース。

運営者について