複合書式指定

.NET の複合書式指定機能は、オブジェクトのリストおよび複合書式指定文字列を入力として使用します。 複合書式指定文字列は、固定テキストに、書式指定項目と呼ばれるインデックス化されたプレースホルダーが混合されて構成されます。 この書式指定項目は、リスト内のオブジェクトに対応します。 書式設定操作によって生成される結果の文字列は、元の固定テキストに文字列で表されたリスト内のオブジェクトが混合されて構成されます。

重要

使用している言語とそのバージョンでサポートされている場合、複合書式指定文字列を使用する代わりに、"補間された文字列" を使用することができます。 補間された文字列には、"補間された式" が含まれています。 各挿入式は式の値によって解かれ、文字列が割り当てられるとき、結果文字列に含まれます。 詳細については、文字列補間 (C# リファレンス) および補間文字列 (Visual Basic リファレンス) に関するページを参照してください。

次のメソッドは、複合書式指定機能をサポートしています。

複合書式指定文字列

複合書式指定文字列とオブジェクト リストは、複合書式指定機能をサポートするメソッドの引数として使用されます。 複合書式指定文字列は、1 つ以上の書式指定項目が混合された 0 個以上の固定テキストで構成されます。 固定テキストはユーザーが任意に選択した文字列で、各書式指定項目はリスト内のオブジェクトまたはボックス化された構造体に対応します。 各オブジェクトの文字列表現は、対応する書式指定項目を置き換えます。

次の Format コードがあるとします。

string.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now);
String.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now)

固定テキストは、Name = および , hours = です。 書式指定項目は {0} であり、その 0 のインデックスはオブジェクト name{1:hh} に対応します。1 のインデックスはオブジェクト DateTime.Now に対応します。

書式指定項目の構文

各書式指定項目は、次の形式を使用し、次のコンポーネントで構成されます。

{index[,alignment][:formatString]}

対になった中かっこ ({}) が必要です。

Index コンポーネント

必須の index コンポーネントは、パラメータ指定子とも呼ばれ、オブジェクトのリスト内で対応する項目を識別するための 0 から始まる数値です。 つまり、パラメータ指定子が 0 の書式指定項目は、リスト内の最初のオブジェクトを書式設定します。 パラメータ指定子が 1 の書式指定項目は、リスト内の 2 番目のオブジェクトを書式設定します。以下同様です。 次の例には、10 未満の素数を表す 4 つのパラメーター指定子 (0 から 3 の番号が付けられている) が含まれています。

string.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now);
String.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now)

同じパラメーター指定子を指定することによって、複数の書式指定項目でオブジェクトのリスト内の同じ要素を参照できます。 たとえば、次の例に示すように、複合書式文字列 ("0x{0:X} {0:E} {0:N}" など) を指定すると、16 進数、指数、数字形式で同じ数値の書式を指定できます。

string multiple = string.Format("0x{0:X} {0:E} {0:N}",
                                Int64.MaxValue);
Console.WriteLine(multiple);

// The example displays the following output:
//      0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00
Dim multiple As String = String.Format("0x{0:X} {0:E} {0:N}",
                                       Int64.MaxValue)
Console.WriteLine(multiple)

'The example displays the following output
'     0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00

各書式指定項目は、リスト内のどのオブジェクトでも参照できます。 たとえば、3 つのオブジェクトがある場合は、{1} {0} {2} などの複合書式文字列を指定して、2 番目、1 番目、3 番目のオブジェクトの書式を指定できます。 書式指定項目で参照されないオブジェクトは無視されます。 パラメーター指定子がオブジェクトのリストの範囲外の項目を指定する場合は、実行時に FormatException がスローされます。

Alignment コンポーネント

省略可能な alignment コンポーネントは、書式設定フィールドの幅を指定する符号付き整数です。 alignment の値が書式設定する文字列の長さよりも小さい場合、alignment は無視され、書式設定する文字列の長さがフィールドの幅として使用されます。 フィールド内の書式設定されたデータは、alignment が正の場合は右揃え、alignment が負の場合は左揃えされます。 埋め込みが必要な場合は、空白が使用されます。 alignment を指定する場合は、コンマが必要です。

次の例では、2 つの配列を定義します。1 つの配列には従業員の名前が含まれていて、もう 1 つの配列には従業員が 2 週間にわたって作業した時間数が含まれています。 複合書式指定文字列では、名前が 20 文字のフィールドに左揃えに指定され、時間数が 5 文字のフィールドに右揃えに指定されます。 "N1" 標準書式指定文字列は、時間を 1 桁の小数部で書式設定します。

string[] names = { "Adam", "Bridgette", "Carla", "Daniel",
                   "Ebenezer", "Francine", "George" };
decimal[] hours = { 40, 6.667m, 40.39m, 82,
                    40.333m, 80, 16.75m };

Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours");

for (int counter = 0; counter < names.Length; counter++)
    Console.WriteLine("{0,-20} {1,5:N1}", names[counter], hours[counter]);

// The example displays the following output:
//      Name                 Hours
//      
//      Adam                  40.0
//      Bridgette              6.7
//      Carla                 40.4
//      Daniel                82.0
//      Ebenezer              40.3
//      Francine              80.0
//      George                16.8
Dim names As String() = {"Adam", "Bridgette", "Carla", "Daniel",
                         "Ebenezer", "Francine", "George"}

Dim hours As Decimal() = {40, 6.667D, 40.39D, 82,
                          40.333D, 80, 16.75D}

Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours")

For counter = 0 To names.Length - 1
    Console.WriteLine("{0,-20} {1,5:N1}", names(counter), hours(counter))
Next

'The example displays the following output
'     Name                 Hours
'     
'     Adam                  40.0
'     Bridgette              6.7
'     Carla                 40.4
'     Daniel                82.0
'     Ebenezer              40.3
'     Francine              80.0
'     George                16.8

Format String コンポーネント

オプションの formatString コンポーネントは、書式設定されるオブジェクトの種類に適した書式指定文字列です。 以下を指定できます。

  • 対応するオブジェクトが数値の場合は、標準またはカスタムの数値書式指定文字列。
  • 対応するオブジェクトが DateTime オブジェクトの場合は、標準またはカスタムの日時書式指定文字列。
  • 対応するオブジェクトが列挙値の場合は、列挙型書式指定文字列

formatString が指定されない場合は、数値、日付と時刻、または列挙型の汎用 ("G") 書式指定子が使用されます。 formatString を指定する場合はコロンが必要です。

次の表に、事前定義された一連の書式指定文字列がサポートされる .NET クラス ライブラリの型または型のカテゴリの一覧、およびサポートされる書式指定文字列について記述されている記事へのリンクを示します。 文字列の書式設定とは拡張可能な機構で、既存のすべての型に対する新しい書式指定文字列を定義したり、アプリケーション定義の型でサポートされる一連の書式指定文字列を定義したりできます。

詳細については、IFormattableICustomFormatter のインターフェイスに関する記事を参照してください。

型または型のカテゴリ 解決方法については、
日付と時刻の型 (DateTimeDateTimeOffset) 標準の日時形式文字列

カスタム日時形式文字列
列挙型 (System.Enum から派生したすべての型) 列挙型書式指定文字列
数値型 (BigIntegerByteDecimalDoubleInt16Int32Int64SByteSingleUInt16UInt32UInt64) 標準の数値書式指定文字列

カスタム数値形式文字列
Guid Guid.ToString(String)
TimeSpan 標準の時間間隔書式指定文字列

カスタム時間間隔書式指定文字列

エスケープ中かっこ ({})

左中かっこ ({) および右中かっこ (}) は、書式指定項目の開始および終了として解釈されます。 リテラルの左中かっこおよび右中かっこを表示するためには、エスケープ シーケンスを使用する必要があります。 左中かっこを 1 つ ({) 表示するには、左中かっこ 2 つ ({{) を固定テキストに指定します。また、右中かっこを 1 つ (}) 表示するには、右中かっこ 2 つ (}}) を指定します。

書式指定項目を含むエスケープされた中かっこは、.NET と .NET Framework では異なる方法で解析されます。

.NET

書式指定項目を囲む中かっこをエスケープできます。 たとえば、書式指定項目 {{{0:D}}} があるとします。これは、左中かっこ、10 進数で表記された数値、右中かっこを表示することを意図しています。 この書式指定項目は、次のように解釈されます。

  1. 最初の 2 つの左中かっこ ({{) がエスケープされ、左中かっこ 1 つが作成されます。
  2. 次の 3 文字 ({0:) は、書式指定項目の開始として解釈されます。
  3. 次の文字 (D) は、10 進標準数値書式指定子として解釈されます。
  4. 次の中かっこ (}) は、書式指定項目の終わりとして解釈されます。
  5. 最後の 2 つの右中かっこはエスケープされ、1 つの右中かっこが生成されます。
  6. 最終的には、{6324} というリテラル文字列が表示されます。
int value = 6324;
string output = string.Format("{{{0:D}}}", value);

Console.WriteLine(output);
// The example displays the following output:
//       {6324}
Dim value As Integer = 6324
Dim output As String = String.Format("{{{0:D}}}", value)

Console.WriteLine(output)

'The example displays the following output
'      {6324}

.NET Framework

書式指定項目に使用されている中かっこは、指定されている順序に従って解釈されます。 入れ子になった中かっこを解釈する機能はサポートされていません。

エスケープされた中かっこの解釈によっては、予測しない結果になる場合があります。 たとえば、書式指定項目 {{{0:D}}} があるとします。これは、左中かっこ、10 進数で表記された数値、右中かっこを表示することを意図しています。 しかし、この書式指定項目は、次のように解釈されます。

  1. 最初の 2 つの左中かっこ ({{) がエスケープされ、左中かっこ 1 つが作成されます。
  2. 次の 3 文字 ({0:) は、書式指定項目の開始として解釈されます。
  3. 次の文字 (D) は、Decimal 標準数値書式指定子として解釈できますが、エスケープされた次の 2 つの右中かっこ (}}) からは単一の中かっこが作成されます。 結果として作成される文字列 (D}) は、標準数値書式指定子ではないため、リテラル文字列 D} の表示を意味するカスタム書式指定文字列として解釈されます。
  4. 最後の中かっこ (}) は、書式指定項目の終わりとして解釈されます。
  5. 最終的には、{D} というリテラル文字列が表示されます。 書式設定対象だった数値は、表示されません。
int value = 6324;
string output = string.Format("{{{0:D}}}",
                              value);
Console.WriteLine(output);

// The example displays the following output:
//       {D}
Dim value As Integer = 6324
Dim output As String = String.Format("{{{0:D}}}",
                                     value)
Console.WriteLine(output)

'The example displays the following output:
'      {D}

エスケープした中かっこと書式指定項目とが誤って解釈されないコードを記述するためには、中かっこと書式指定項目を別々に書式設定するという方法があります。 つまり、最初の書式指定操作では、リテラルの左中かっこを表示します。 次の操作では、書式指定項目の結果を表示し、最後の操作ではリテラルの右中かっこを表示します。 このアプローチの例を次に示します。

int value = 6324;
string output = string.Format("{0}{1:D}{2}",
                             "{", value, "}");
Console.WriteLine(output);

// The example displays the following output:
//       {6324}
Dim value As Integer = 6324
Dim output As String = String.Format("{0}{1:D}{2}",
                                     "{", value, "}")
Console.WriteLine(output)

'The example displays the following output:
'      {6324}

処理の順序

複合書式指定メソッドの呼び出しに、値が null でない IFormatProvider 引数が含まれている場合、ランタイムはその IFormatProvider.GetFormat メソッドを呼び出して、ICustomFormatter 実装を要求します。 このメソッドが ICustomFormatter 実装を返すことができる場合、その実装は複合書式指定メソッドの呼び出し中にキャッシュされます。

書式指定項目に対応するパラメーター リストのそれぞれの値は、次のように文字列に変換されます。

  1. 書式設定する値が null の場合は、空の文字列 String.Empty が返されます。

  2. ICustomFormatter 実装が利用できる場合、ランタイムはその Format メソッドを呼び出します。 ランタイムは、書式指定項目の formatString 値 (存在しない場合は null) をメソッドに渡します。 ランタイムでは、IFormatProvider の実装もメソッドに渡されます。 ICustomFormatter.Format メソッドの呼び出しから null が返ると、実行は次のステップに進みます。 それ以外の場合は、ICustomFormatter.Format 呼び出しの結果が返されます。

  3. 値が IFormattable インターフェイスを実装している場合は、インターフェイスの ToString(String, IFormatProvider) メソッドが呼び出されます。 それが書式指定項目にある場合、formatString 値がメソッドに渡されます。 それ以外の場合は、null が渡されます。 IFormatProvider 引数は、次のように判断されます。

    • 数値の場合、null 以外の IFormatProvider 引数を持つ複合書式指定メソッドが呼び出されると、ランタイムは IFormatProvider.GetFormat メソッドから NumberFormatInfo オブジェクトを要求します。 そのオブジェクトを取得できないか、引数の値が null であるか、または複合書式指定メソッドに IFormatProvider パラメーターがない場合は、現在のカルチャの NumberFormatInfo オブジェクトが使用されます。

    • 日付と時刻の値の場合、null 以外の IFormatProvider 引数を持つ複合書式指定メソッドが呼び出されると、ランタイムは IFormatProvider.GetFormat メソッドから DateTimeFormatInfo オブジェクトを要求します。 次の状況では、代わりに現在のカルチャの DateTimeFormatInfo オブジェクトが使用されます。

    • 他の型のオブジェクトの場合、IFormatProvider 引数を使用して複合書式のメソッドを呼び出すと、その値は IFormattable.ToString 実装に直接渡されます。 それ以外の場合は、nullIFormattable.ToString 実装に渡されます。

  4. ToString をオーバーライドするか、基底クラスの動作を継承する、型のパラメーターなしの Object.ToString() メソッドが呼び出されます。 この場合、書式指定項目の formatString コンポーネントで指定されている書式指定文字列は、存在していても無視されます。

前の手順が実行された後、アラインメントが適用されます。

コード例

複合書式指定を使用して文字列を作成する方法と、オブジェクトの ToString メソッドを使用して文字列を作成する方法を示すコード例を次に示します。 この 2 つの書式設定方法では、等価の文字列が作成されます。

string formatString1 = string.Format("{0:dddd MMMM}", DateTime.Now);
string formatString2 = DateTime.Now.ToString("dddd MMMM");
Dim formatString1 As String = String.Format("{0:dddd MMMM}", DateTime.Now)
Dim formatString2 As String = DateTime.Now.ToString("dddd MMMM")

現在の曜日が木曜日であり、月が 5 月であり、現在のカルチャが英語 (U.S.) の場合、上記のコード例で作成される 2 つの文字列の値はどちらも Thursday Mayです。

Console.WriteLine は、String.Format と同じ機能を公開します。 これら 2 つのメソッドの唯一の違いは、String.Format が結果を文字列で返すのに対し、Console.WriteLine は、Console オブジェクトに関連付けられた出力ストリームに結果を書き出す点です。 Console.WriteLine メソッドを使用して値 myNumber を通貨値として書式設定する例を次に示します。

int myNumber = 100;
Console.WriteLine("{0:C}", myNumber);

// The example displays the following output
// if en-US is the current culture:
//        $100.00
Dim myNumber As Integer = 100
Console.WriteLine("{0:C}", myNumber)

'The example displays the following output
'if en-US Is the current culture:
'       $100.00

1 つのオブジェクトを 2 つの方法で書式設定する例を含め、複数のオブジェクトを書式設定する例を次に示します。

string myName = "Fred";
Console.WriteLine(string.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
                                myName, DateTime.Now));

// Depending on the current time, the example displays output like the following:
//        Name = Fred, hours = 11, minutes = 30
Dim myName As String = "Fred"
Console.WriteLine(String.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
                                myName, DateTime.Now))
'Depending on the current time, the example displays output Like the following:
'       Name = Fred, hours = 11, minutes = 30

書式設定でアラインメントを使用する方法を示す例を次に示します。 アラインメント結果を強調表示するため、書式が設定される引数を縦棒 (|) で囲んでいます。

string firstName = "Fred";
string lastName = "Opals";
int myNumber = 100;

string formatFirstName = string.Format("First Name = |{0,10}|", firstName);
string formatLastName = string.Format("Last Name =  |{0,10}|", lastName);
string formatPrice = string.Format("Price =      |{0,10:C}|", myNumber);
Console.WriteLine(formatFirstName);
Console.WriteLine(formatLastName);
Console.WriteLine(formatPrice);
Console.WriteLine();

formatFirstName = string.Format("First Name = |{0,-10}|", firstName);
formatLastName = string.Format("Last Name =  |{0,-10}|", lastName);
formatPrice = string.Format("Price =      |{0,-10:C}|", myNumber);
Console.WriteLine(formatFirstName);
Console.WriteLine(formatLastName);
Console.WriteLine(formatPrice);

// The example displays the following output on a system whose current
// culture is en-US:
//     First Name = |      Fred|
//     Last Name =  |     Opals|
//     Price =      |   $100.00|
//
//     First Name = |Fred      |
//     Last Name =  |Opals     |
//     Price =      |$100.00   |
Dim firstName As String = "Fred"
Dim lastName As String = "Opals"
Dim myNumber As Integer = 100

Dim formatFirstName As String = String.Format("First Name = |{0,10}|", firstName)
Dim formatLastName As String = String.Format("Last Name =  |{0,10}|", lastName)
Dim formatPrice As String = String.Format("Price =      |{0,10:C}|", myNumber)
Console.WriteLine(formatFirstName)
Console.WriteLine(formatLastName)
Console.WriteLine(formatPrice)
Console.WriteLine()

formatFirstName = String.Format("First Name = |{0,-10}|", firstName)
formatLastName = String.Format("Last Name =  |{0,-10}|", lastName)
formatPrice = String.Format("Price =      |{0,-10:C}|", myNumber)
Console.WriteLine(formatFirstName)
Console.WriteLine(formatLastName)
Console.WriteLine(formatPrice)

'The example displays the following output on a system whose current
'culture Is en-US:
'    First Name = |      Fred|
'    Last Name =  |     Opals|
'    Price =      |   $100.00|
'
'    First Name = |Fred      |
'    Last Name =  |Opals     |
'    Price =      |$100.00   |

関連項目