NumberFormatInfo クラス

この記事では、この API のリファレンス ドキュメントへの補足的な解説を提供します。

この NumberFormatInfo クラスには、数値の書式設定と解析を行うときに使用されるカルチャ固有の情報が含まれています。 この情報には、通貨記号、小数点記号、グループ区切り記号、正符号と負符号の記号が含まれます。

NumberFormatInfo オブジェクトのインスタンスを作成する

現在のカルチャ、インバリアント カルチャ、特定のカルチャ、またはニュートラル カルチャの書式設定規則を表す NumberFormatInfo オブジェクトのインスタンスを作成することができます。

現在のカルチャの NumberFormatInfo オブジェクトのインスタンスを作成する

以下のいずれかの方法で現在のカルチャの NumberFormatInfo オブジェクトのインスタンスを作成できます。 いずれの場合も、返される NumberFormatInfo オブジェクトは読み取り専用です。

次の例では、これら 3 つの方法を使用して、現在のカルチャの書式設定規則を表す NumberFormatInfo オブジェクトを作成します。 また、各オブジェクトが読み取り専用であることを示すために、IsReadOnly プロパティの値も取得します。

using System;
using System.Globalization;

public class InstantiateEx1
{
    public static void Main()
    {
        NumberFormatInfo current1 = CultureInfo.CurrentCulture.NumberFormat;
        Console.WriteLine(current1.IsReadOnly);

        NumberFormatInfo current2 = NumberFormatInfo.CurrentInfo;
        Console.WriteLine(current2.IsReadOnly);

        NumberFormatInfo current3 = NumberFormatInfo.GetInstance(CultureInfo.CurrentCulture);
        Console.WriteLine(current3.IsReadOnly);
    }
}
// The example displays the following output:
//       True
//       True
//       True

以下のいずれかの方法で、現在のカルチャの規則を表す書き込み可能な NumberFormatInfo オブジェクトを作成できます。

次の例は、NumberFormatInfo オブジェクトのインスタンスを作成するこれら 2 つの方法を示し、その IsReadOnly プロパティの値を表示して、このオブジェクトが読み取り専用ではないことを示します。

using System;
using System.Globalization;

public class InstantiateEx2
{
    public static void Main()
    {
        NumberFormatInfo current1 = NumberFormatInfo.CurrentInfo;
        current1 = (NumberFormatInfo)current1.Clone();
        Console.WriteLine(current1.IsReadOnly);

        CultureInfo culture2 = CultureInfo.CreateSpecificCulture(CultureInfo.CurrentCulture.Name);
        NumberFormatInfo current2 = culture2.NumberFormat;
        Console.WriteLine(current2.IsReadOnly);
    }
}
// The example displays the following output:
//       False
//       False

Windows オペレーティング システムでは、ユーザーは、コントロール パネルの地域と言語アイテムを通じて数値の書式設定と解析操作で使用される NumberFormatInfo プロパティの値の一部をオーバーライドできることに注意してください。 たとえば、カルチャが英語 (米国) となっているユーザーは、通貨の値を既定値の $1.1 ではなく 1.1 USD と表示することを選択できます。 先ほど説明した方法で取得した NumberFormatInfo オブジェクトは、これらのユーザーのオーバーライドのすべてを反映します。 これが望ましくない場合は、CultureInfo.CultureInfo(String, Boolean) コンストラクターを呼び出して useUserOverride 引数に false 値を与えることで、ユーザーのオーバーライドを反映しない (かつ読み取り専用ではなく読み取り/書き込み可能な) NumberFormatInfo オブジェクトを作成できます。 次の例では、現在のカルチャが英語 (米国) で、通貨記号が既定の $ から USD に変更されたシステムの例を示します。

using System;
using System.Globalization;

public class InstantiateEx3
{
    public static void Main()
    {
        CultureInfo culture;
        NumberFormatInfo nfi;

        culture = CultureInfo.CurrentCulture;
        nfi = culture.NumberFormat;
        Console.WriteLine("Culture Name:    {0}", culture.Name);
        Console.WriteLine("User Overrides:  {0}", culture.UseUserOverride);
        Console.WriteLine("Currency Symbol: {0}\n", culture.NumberFormat.CurrencySymbol);

        culture = new CultureInfo(CultureInfo.CurrentCulture.Name, false);
        Console.WriteLine("Culture Name:    {0}", culture.Name);
        Console.WriteLine("User Overrides:  {0}", culture.UseUserOverride);
        Console.WriteLine("Currency Symbol: {0}", culture.NumberFormat.CurrencySymbol);
    }
}
// The example displays the following output:
//       Culture Name:    en-US
//       User Overrides:  True
//       Currency Symbol: USD
//
//       Culture Name:    en-US
//       User Overrides:  False
//       Currency Symbol: $

CultureInfo.UseUserOverride プロパティが true に設定されていると、ユーザー設定からはプロパティ CultureInfo.DateTimeFormatCultureInfo.NumberFormatCultureInfo.TextInfo も取得されます。 ユーザー設定が CultureInfo オブジェクトに関連付けられているカルチャと互換性がない場合 (たとえば、選択したカレンダーが OptionalCalendars プロパティにリストアップされているカレンダーのいずれかでない場合)、メソッドの結果とプロパティの値は未定義になります。

インバリアント カルチャの NumberFormatInfo オブジェクトのインスタンスを作成する

インバリアント カルチャは、カルチャに依存しないカルチャを表します。 これは英語をベースとしますが、英語を話す特定の国/地域はベースとしません。 特定のカルチャのデータは動的であり、新しいカルチャに関する規則やユーザー設定を反映するように変化する可能性がありますが、インバリアント カルチャのデータは変化しません。 インバリアント カルチャの書式設定規則を表す NumberFormatInfo オブジェクトは、結果文字列がカルチャごとに異なってはならない書式設定操作に使用できます。

インバリアント カルチャの書式設定規則を表す NumberFormatInfo オブジェクトは、以下の方法でインスタンスを作成できます。

次の例では、これらの各メソッドを使用して、インバリアント カルチャを表す NumberFormatInfo オブジェクトのインスタンスを作成します。 次に、オブジェクトが読み取り専用かどうかを示します。

using System;
using System.Globalization;

public class InstantiateEx4
{
    public static void Main()
    {
        NumberFormatInfo nfi;

        nfi = System.Globalization.NumberFormatInfo.InvariantInfo;
        Console.WriteLine(nfi.IsReadOnly);

        nfi = CultureInfo.InvariantCulture.NumberFormat;
        Console.WriteLine(nfi.IsReadOnly);

        nfi = new NumberFormatInfo();
        Console.WriteLine(nfi.IsReadOnly);
    }
}
// The example displays the following output:
//       True
//       True
//       False

特定のカルチャの NumberFormatInfo オブジェクトのインスタンスを作成する

特定のカルチャは、特定の国/地域で話される言語を表します。 たとえば、en-US は米国で話される英語を表す特定のカルチャであり、en-CA はカナダで話される英語を表す特定のカルチャです。 特定のカルチャの書式設定規則を表す NumberFormatInfo オブジェクトは、以下の方法でインスタンスを作成できます。

次の例では、これら 4 つの方法を使用して、インドネシア語 (インドネシア) カルチャの書式設定規則を反映する NumberFormatInfo オブジェクトを作成します。 また、各オブジェクトが読み取り専用かどうかを示します。

using System;
using System.Globalization;

public class InstantiateEx5
{
    public static void Main()
    {
        CultureInfo culture;
        NumberFormatInfo nfi;

        nfi = CultureInfo.GetCultureInfo("id-ID").NumberFormat;
        Console.WriteLine("Read-only: {0}", nfi.IsReadOnly);

        culture = new CultureInfo("id-ID");
        nfi = NumberFormatInfo.GetInstance(culture);
        Console.WriteLine("Read-only: {0}", nfi.IsReadOnly);

        culture = CultureInfo.CreateSpecificCulture("id-ID");
        nfi = culture.NumberFormat;
        Console.WriteLine("Read-only: {0}", nfi.IsReadOnly);

        culture = new CultureInfo("id-ID");
        nfi = culture.NumberFormat;
        Console.WriteLine("Read-only: {0}", nfi.IsReadOnly);
    }
}
// The example displays the following output:
//       Read-only: True
//       Read-only: False
//       Read-only: False
//       Read-only: False

ニュートラル カルチャの NumberFormatInfo オブジェクトのインスタンスを作成する

ニュートラル カルチャは、国/地域に依存しないカルチャまたは言語を表します。 通常、これは 1 つ以上の特定のカルチャの親です。 たとえば、fr はフランス語のニュートラル カルチャであり、fr-FR カルチャの親です。 ニュートラル カルチャの書式設定規則を表す NumberFormatInfo オブジェクトは、特定のカルチャの書式設定規則を表す NumberFormatInfo オブジェクトを作成するのと同じ方法で作成します。

ただし、ニュートラル カルチャは特定の国/地域に依存しないため、ニュートラル カルチャにはカルチャ固有の書式設定情報がありません。 .NET は、NumberFormatInfo オブジェクトに汎用値を設定するのではなく、ニュートラル カルチャの子である特定のカルチャの書式設定規則を反映する NumberFormatInfo オブジェクトを返します。 たとえば、ニュートラルな en カルチャの NumberFormatInfo オブジェクトは en-US カルチャの書式設定規則を反映し、fr カルチャの NumberFormatInfo オブジェクトは fr-FR カルチャの書式設定規則を反映します。

次のようなコードを使用して、各ニュートラル カルチャが表す特定のカルチャの書式設定規則を判別できます。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;

public class InstantiateEx6
{
    public static void Main()
    {
        // Get all the neutral cultures
        List<String> names = new List<String>();
        Array.ForEach(CultureInfo.GetCultures(CultureTypes.NeutralCultures),
                      culture => names.Add(culture.Name));
        names.Sort();
        foreach (var name in names)
        {
            // Ignore the invariant culture.
            if (name == "") continue;

            ListSimilarChildCultures(name);
        }
    }

    private static void ListSimilarChildCultures(string name)
    {
        // Create the neutral NumberFormatInfo object.
        NumberFormatInfo nfi = CultureInfo.GetCultureInfo(name).NumberFormat;
        // Retrieve all specific cultures of the neutral culture.
        CultureInfo[] cultures = Array.FindAll(CultureInfo.GetCultures(CultureTypes.SpecificCultures),
                                 culture => culture.Name.StartsWith(name + "-", StringComparison.OrdinalIgnoreCase));
        // Create an array of NumberFormatInfo properties
        PropertyInfo[] properties = typeof(NumberFormatInfo).GetProperties(BindingFlags.Instance | BindingFlags.Public);
        bool hasOneMatch = false;

        foreach (var ci in cultures)
        {
            bool match = true;
            // Get the NumberFormatInfo for a specific culture.
            NumberFormatInfo specificNfi = ci.NumberFormat;
            // Compare the property values of the two.
            foreach (var prop in properties)
            {
                // We're not interested in the value of IsReadOnly.
                if (prop.Name == "IsReadOnly") continue;

                // For arrays, iterate the individual elements to see if they are the same.
                if (prop.PropertyType.IsArray)
                {
                    IList nList = (IList)prop.GetValue(nfi, null);
                    IList sList = (IList)prop.GetValue(specificNfi, null);
                    if (nList.Count != sList.Count)
                    {
                        match = false;
                        break;
                    }

                    for (int ctr = 0; ctr < nList.Count; ctr++)
                    {
                        if (!nList[ctr].Equals(sList[ctr]))
                        {
                            match = false;
                            break;
                        }
                    }
                }
                else if (!prop.GetValue(specificNfi).Equals(prop.GetValue(nfi)))
                {
                    match = false;
                    break;
                }
            }
            if (match)
            {
                Console.WriteLine("NumberFormatInfo object for '{0}' matches '{1}'",
                                          name, ci.Name);
                hasOneMatch = true;
            }
        }
        if (!hasOneMatch)
            Console.WriteLine("NumberFormatInfo object for '{0}' --> No Match", name);

        Console.WriteLine();
    }
}

動的データ

NumberFormatInfo クラスによって提供される数値を書式設定するためのカルチャ固有のデータは、CultureInfo クラスによって提供されるカルチャ データと同様に動的です。 特定の CultureInfo オブジェクトに関連付けられている NumberFormatInfo オブジェクトの値の安定性に関してはどのような仮定も行うべきではありません。 安定しているのは、インバリアント カルチャとそれに関連付けられている NumberFormatInfo オブジェクトによって提供されるデータだけです。 その他のデータは、アプリケーション セッション間、または単一セッション内でも、以下の理由によって変化する可能性があります。

  • システムの更新プログラム。 通貨記号や通貨形式などのカルチャ設定は、時間の経過と共に変化します。 この場合、Windows Update は、特定のカルチャの NumberFormatInfo プロパティ値に変更内容を含めます。

  • 置換カルチャ。 CultureAndRegionInfoBuilder クラスは、既存カルチャのデータを置き換えるために使用されます。

  • プロパティ値に対する連鎖的変更。 いくつかのカルチャ関連プロパティは実行時に変化する可能性があり、その結果、NumberFormatInfo データが変化します。 たとえば、現在のカルチャは、プログラム的に、またはユーザー アクション通じて変更される可能性があります。 この場合、CurrentInfo プロパティによって返される NumberFormatInfo オブジェクトは、現在のカルチャに関連付けられているオブジェクトに変化します。

  • ユーザー設定。 アプリケーションのユーザーは、コントロール パネルの地域と言語オプションを通して、現在のシステム カルチャに関連付けられている値の一部をオーバーライドする場合があります。 たとえば、ユーザーは別の通貨記号または別の小数点記号を選択する場合があります。 CultureInfo.UseUserOverride プロパティが true (既定値) に設定されている場合、NumberFormatInfo オブジェクトのプロパティもユーザー設定から取得されます。

NumberFormatInfo オブジェクトのユーザーによるオーバーライドが可能なプロパティはすべて、オブジェクトの作成時に初期化されます。 オブジェクトの作成とユーザー オーバーライド プロセスはどちらもアトミックでなく、オブジェクトの作成時に関連する値が変化する場合があるため、不整合が発生する可能性があります。 ただし、このような不整合は極めてまれであると言えます。

ユーザー オーバーライドが、現在のカルチャと同じカルチャを表す NumberFormatInfo オブジェクトに反映されるかどうかを制御できます。 次の表は、NumberFormatInfo オブジェクトを取得できる方法の一覧と、結果オブジェクトがユーザー オーバーライドを反映するかどうかを示しています。

CultureInfo オブジェクトと NumberFormatInfo オブジェクトのソース ユーザー オーバーライドを反映するか
CultureInfo.CurrentCulture.NumberFormat プロパティ はい
NumberFormatInfo.CurrentInfo プロパティ はい
CultureInfo.CreateSpecificCulture メソッド はい
CultureInfo.GetCultureInfo メソッド いいえ
CultureInfo(String) コンストラクター はい
CultureInfo.CultureInfo(String, Boolean) コンストラクター useUserOverride パラメーターの値に依存

そうしないだけのやむを得ない理由がない限りは、クライアント アプリケーションで NumberFormatInfo オブジェクトを使用してユーザー入力の書式設定と解析を行ったり、数値データを表示したりする際には、ユーザー オーバーライドを優先する必要があります。 サーバー アプリケーションや無人アプリケーションの場合は、ユーザー オーバーライドを優先するべきではありません。 ただし、文字列形式で数値データを保持するために NumberFormatInfo オブジェクトを明示的または暗黙的に使用する場合は、インバリアント カルチャの書式設定規則を反映する NumberFormatInfo オブジェクトを使用するか、カルチャに関係なく使用するカスタムの数値書式設定文字列を指定する必要があります。

IFormatProvider、NumberFormatInfo、数値書式設定

NumberFormatInfo オブジェクトは、すべての数値書式設定操作で暗黙的または明示的に使用されます。 これには、以下のメソッドの呼び出しが含まれます。

すべての数値書式設定操作は、IFormatProvider の実装を使用します。 IFormatProvider インターフェイスには単一メソッドである GetFormat(Type) が含まれます。 これは、書式設定情報を提供するために必要な型を表す Type オブジェクトを渡されるコールバック メソッドです。 このメソッドの役割は、その型のインスタンスまたは null (その型のインスタンスを返せない場合) のどちらかを返すことです。 .NET には、数値を書式設定するために、以下の 2 つの IFormatProvider の実装が用意されています。

IFormatProvider の実装が書式設定メソッドに明示的に渡されない場合は、現在のカルチャを表す CultureInfo.CurrentCulture プロパティによって返される CultureInfo オブジェクトが使用されます。

次の例は、カスタムの IFormatProvider の実装を定義することで、書式設定操作における IFormatProvider インターフェイスと NumberFormatInfo クラスの間の関係を明らかにします。 この GetFormat メソッドは、書式設定操作によって要求されたオブジェクトの型名を表示します。 インターフェイスが NumberFormatInfo オブジェクトを要求している場合、このメソッドは現在のカルチャの NumberFormatInfo オブジェクトを提供します。 この例の出力が示すように、Decimal.ToString(IFormatProvider) メソッドは書式設定情報を提供するために NumberFormatInfo オブジェクトを必要とする一方、String.Format(IFormatProvider, String, Object[]) メソッドは ICustomFormatter の実装に加え、NumberFormatInfo および DateTimeFormatInfo オブジェクトを必要とします。

using System;
using System.Globalization;

public class CurrentCultureFormatProvider : IFormatProvider
{
    public Object GetFormat(Type formatType)
    {
        Console.WriteLine("Requesting an object of type {0}",
                          formatType.Name);
        if (formatType == typeof(NumberFormatInfo))
            return NumberFormatInfo.CurrentInfo;
        else if (formatType == typeof(DateTimeFormatInfo))
            return DateTimeFormatInfo.CurrentInfo;
        else
            return null;
    }
}

public class FormatProviderEx
{
    public static void Main()
    {
        Decimal amount = 1203.541m;
        string value = amount.ToString("C2", new CurrentCultureFormatProvider());
        Console.WriteLine(value);
        Console.WriteLine();
        string composite = String.Format(new CurrentCultureFormatProvider(),
                                         "Date: {0}   Amount: {1}   Description: {2}",
                                         DateTime.Now, 1264.03m, "Service Charge");
        Console.WriteLine(composite);
        Console.WriteLine();
    }
}
// The example displays output like the following:
//    Requesting an object of type NumberFormatInfo
//    $1,203.54
//
//    Requesting an object of type ICustomFormatter
//    Requesting an object of type DateTimeFormatInfo
//    Requesting an object of type NumberFormatInfo
//    Date: 11/15/2012 2:00:01 PM   Amount: 1264.03   Description: Service Charge

数値書式設定メソッドの呼び出しで IFormatProvider の実装が明示的に指定されていない場合、このメソッドは CultureInfo.CurrentCulture.GetFormat メソッドを呼び出し、これによって現在のカルチャに対応する NumberFormatInfo オブジェクトが返されます。

書式設定文字列と NumberFormatInfo プロパティ

すべての書式設定操作は、標準またはカスタムのどちらかの数値書式設定文字列を使用して、数値から結果文字列を生成します。 いくつかのケースでは、結果文字列を生成するための書式設定文字列の使用は、次の例のように明示的です。 このコードは、en-US カルチャの書式設定規則を使用して Decimal 値をさまざまな文字列表現に変換する Decimal.ToString(IFormatProvider) メソッドを呼び出します。

using System;
using System.Globalization;

public class PropertiesEx1
{
    public static void Main()
    {
        string[] formatStrings = { "C2", "E1", "F", "G3", "N",
                                 "#,##0.000", "0,000,000,000.0##" };
        CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
        Decimal[] values = { 1345.6538m, 1921651.16m };

        foreach (var value in values)
        {
            foreach (var formatString in formatStrings)
            {
                string resultString = value.ToString(formatString, culture);
                Console.WriteLine("{0,-18} -->  {1}", formatString, resultString);
            }
            Console.WriteLine();
        }
    }
}
// The example displays the following output:
//       C2                 -->  $1,345.65
//       E1                 -->  1.3E+003
//       F                  -->  1345.65
//       G3                 -->  1.35E+03
//       N                  -->  1,345.65
//       #,##0.000          -->  1,345.654
//       0,000,000,000.0##  -->  0,000,001,345.654
//
//       C2                 -->  $1,921,651.16
//       E1                 -->  1.9E+006
//       F                  -->  1921651.16
//       G3                 -->  1.92E+06
//       N                  -->  1,921,651.16
//       #,##0.000          -->  1,921,651.160
//       0,000,000,000.0##  -->  0,001,921,651.16

その他のケースでは、書式設定文字列の使用は暗黙的です。 たとえば、以下の既定またはパラメーターなしの Decimal.ToString() メソッドの呼び出しでは、Decimal インスタンスの値は、一般的な ("G") 書式指定子と現在のカルチャの規則 (この場合は en-US カルチャ) を使用して書式設定されます。

using System;

public class PropertiesEx2
{
    public static void Main()
    {
        Decimal[] values = { 1345.6538m, 1921651.16m };

        foreach (var value in values)
        {
            string resultString = value.ToString();
            Console.WriteLine(resultString);
            Console.WriteLine();
        }
    }
}
// The example displays the following output:
//       1345.6538
//
//       1921651.16

各標準数値書式設定文字列は、1 つ以上の NumberFormatInfo プロパティを使用して、結果文字列で使用されるパターンまたは記号を決定します。 同様に、"0" と "#" を除く各カスタム数値書式指定子は、NumberFormatInfo プロパティによって定義される結果文字列内の記号を挿入します。 次の表は、標準およびカスタムの数値書式指定子とそれに関連する NumberFormatInfo プロパティを一覧表示したものです。 特定のカルチャで結果文字列の見た目を変更するには、「NumberFormatInfo プロパティを変更する」セクションを参照してください。 これらの書式指定子の使用方法の詳細については、「標準数値書式設定文字列」および「カスタム数値書式設定文字列」を参照してください。

書式指定子 関連するプロパティ
"C" または "c" (通貨書式指定子) CurrencyDecimalDigits: 小数部の既定の桁数を定義します。

CurrencyDecimalSeparator (小数点の記号を定義します)。

CurrencyGroupSeparator: グループまたは 3 桁区切りを定義します。

CurrencyGroupSizes: 整数グループのサイズを定義します。

CurrencyNegativePattern: 負の通貨値のパターンを定義します。

CurrencyPositivePattern: 正の通貨値のパターンを定義します。

CurrencySymbol: 通貨記号を定義します。

NegativeSign (マイナス記号を定義します)。
"D" または "d" (10 進書式指定子) NegativeSign (マイナス記号を定義します)。
"E" または "e" (指数または科学書式指定子) NegativeSign: 仮数と指数の負符号記号を定義します。

NumberDecimalSeparator (小数点の記号を定義します)。

PositiveSign: 指数の正符号記号を定義します。
"F" または "f" (固定小数点書式指定子) NegativeSign (マイナス記号を定義します)。

NumberDecimalDigits: 小数部の既定の桁数を定義します。

NumberDecimalSeparator (小数点の記号を定義します)。
"G" または "g" (一般書式指定子) NegativeSign (マイナス記号を定義します)。

NumberDecimalSeparator (小数点の記号を定義します)。

PositiveSign: 指数形式の結果文字列の正符号記号を定義します。
"N" または "n" (数値書式指定子) NegativeSign (マイナス記号を定義します)。

NumberDecimalDigits: 小数部の既定の桁数を定義します。

NumberDecimalSeparator (小数点の記号を定義します)。

NumberGroupSeparator: グループ区切り (3 桁区切り) 記号を定義します。

NumberGroupSizes: グループ内の整数桁数を定義します。

NumberNegativePattern: 負の値の形式を定義します。
"P" または "p" (パーセント書式指定子) NegativeSign (マイナス記号を定義します)。

PercentDecimalDigits: 小数部の既定の桁数を定義します。

PercentDecimalSeparator (小数点の記号を定義します)。

PercentGroupSeparator: グループ区切り記号を定義します。

PercentGroupSizes: グループ内の整数桁数を定義します。

PercentNegativePattern: 負の値のパーセント記号と負記号の配置を定義します。

PercentPositivePattern: 正の値のパーセント記号の配置を定義します。

PercentSymbol: パーセント記号を定義します。
"R" または "r" (ラウンドトリップ書式指定子) NegativeSign (マイナス記号を定義します)。

NumberDecimalSeparator (小数点の記号を定義します)。

PositiveSign: 指数の正符号記号を定義します。
"X" または "x" (16 進数書式指定子) なし。
"." (小数点のカスタム書式指定子) NumberDecimalSeparator (小数点の記号を定義します)。
"," (グループ区切りのカスタム書式指定子) NumberGroupSeparator: グループ (3 桁) 区切り記号を定義します。
"%" (パーセンテージ プレースホルダーのカスタム書式指定子) PercentSymbol: パーセント記号を定義します。
"‰" (パーミル プレースホルダーのカスタム書式指定子) PerMilleSymbol: パーミル記号を定義します。
"E" (指数表記のカスタム書式指定子) NegativeSign: 仮数と指数の負符号記号を定義します。

PositiveSign: 指数の正符号記号を定義します。

NumberFormatInfo クラスには、特定のカルチャで使用される基本の 10 個の数字を指定する NativeDigits プロパティが含まれていることに注意してください。 ただし、このプロパティは書式設定操作では使用されず、結果文字列では、基本ラテン数字 0 (U+0030) から 9 (U+0039) までのみが使用されます。 さらに、NaNPositiveInfinityNegativeInfinitySingle および Double 値については、結果文字列はそれぞれ NaNSymbolPositiveInfinitySymbolNegativeInfinitySymbol プロパティによって定義される記号だけから構成されます。

NumberFormatInfo のプロパティを変更する

NumberFormatInfo オブジェクトのプロパティを変更して、数値書式設定操作で生成される結果文字列をカスタマイズできます。 手順は次のとおりです。

  1. 変更したい書式設定規則を持つ NumberFormatInfo オブジェクトの読み取り/書き込みコピーを作成します。 詳細については、「NumberFormatInfo オブジェクトのインスタンスを作成する」セクションを参照してください。

  2. 目的の結果文字列を生成するために使用されるプロパティを変更します。 書式設定メソッドがどのように NumberFormatInfo プロパティを使用して結果文字列を定義するかについては、「書式設定文字列と NumberFormatInfo プロパティ」セクションを参照してください。

  3. 書式設定メソッドの呼び出しで、カスタム NumberFormatInfo オブジェクトを IFormatProvider 引数として使用します。

Note

アプリケーションが起動されるたびにカルチャのプロパティ値を動的に変更する代わりに、CultureAndRegionInfoBuilder クラスを使用してカスタム カルチャ (一意の名前を持ち、既存のカルチャを補完するカルチャ) または置換カルチャ (特定のカルチャの代わりに使用されるカルチャ) を定義できます。

以降のセクションでは、いくつかの例を示します。

通貨記号とパターンを変更する

次の例は、en-US カルチャの書式設定規則を表す NumberFormatInfo オブジェクトを変更します。 ISO-4217 通貨記号を CurrencySymbol プロパティに割り当て、後ろにスペースと数値が続く通貨記号で構成される通貨値のパターンを定義します。

using System;
using System.Globalization;

public class Example
{
    public static void Main()
    {
        // Retrieve a writable NumberFormatInfo object.
        CultureInfo enUS = CultureInfo.CreateSpecificCulture("en-US");
        NumberFormatInfo nfi = enUS.NumberFormat;

        // Use the ISO currency symbol instead of the native currency symbol.
        nfi.CurrencySymbol = (new RegionInfo(enUS.Name)).ISOCurrencySymbol;
        // Change the positive currency pattern to <code><space><value>.
        nfi.CurrencyPositivePattern = 2;
        // Change the negative currency pattern to <code><space><sign><value>.
        nfi.CurrencyNegativePattern = 12;

        // Produce the result strings by calling ToString.
        Decimal[] values = { 1065.23m, 19.89m, -.03m, -175902.32m };
        foreach (var value in values)
            Console.WriteLine(value.ToString("C", enUS));

        Console.WriteLine();

        // Produce the result strings by calling a composite formatting method.
        foreach (var value in values)
            Console.WriteLine(String.Format(enUS, "{0:C}", value));
    }
}
// The example displays the following output:
//       USD 1,065.23
//       USD 19.89
//       USD -0.03
//       USD -175,902.32
//
//       USD 1,065.23
//       USD 19.89
//       USD -0.03
//       USD -175,902.32

国民識別番号を書式設定する

多くの国民識別番号は数字のみで構成されるため、NumberFormatInfo オブジェクトのプロパティを変更することで簡単に書式設定できます。 たとえば、米国の社会保障番号は、次のような配列の 9 個の数字で構成されます: XXX-XX-XXXX。 次の例は、社会保障番号が整数値として保存されていることを想定し、それらを適切に書式設定します。

using System;
using System.Globalization;

public class CustomizeSSNEx
{
    public static void Main()
    {
        // Instantiate a read-only NumberFormatInfo object.
        CultureInfo enUS = CultureInfo.CreateSpecificCulture("en-US");
        NumberFormatInfo nfi = enUS.NumberFormat;

        // Modify the relevant properties.
        nfi.NumberGroupSeparator = "-";
        nfi.NumberGroupSizes = new int[] { 3, 2, 4 };
        nfi.NumberDecimalDigits = 0;

        int[] ids = { 111223333, 999776666 };

        // Produce the result string by calling ToString.
        foreach (var id in ids)
            Console.WriteLine(id.ToString("N", enUS));

        Console.WriteLine();

        // Produce the result string using composite formatting.
        foreach (var id in ids)
            Console.WriteLine(String.Format(enUS, "{0:N}", id));
    }
}
// The example displays the following output:
//       1112-23-333
//       9997-76-666
//
//       1112-23-333
//       9997-76-666

数値文字列の解析

解析には、数値の文字列表現から数値への変換が含まれます。 .NET の各数値型は、ParseTryParse というオーバーロードされた 2 つの解析メソッドを持ちます。 Parse メソッドは、文字列を数値に変換し、変換が失敗した場合は例外をスローします。 TryParse メソッドは、文字列を数値に変換し、その数値を out 引数に割り当て、変換が成功したかどうかを示す Boolean 値を返します。

解析メソッドは、NumberStyles 列挙値を暗黙的または明示的に使用して、解析操作が成功するためには文字列内にどのスタイル要素 (グループ区切り、小数点区切り、通貨記号など) が存在できるかを定義します。 メソッド呼び出しで NumberStyles 値が指定されていない場合、既定値は、Float および AllowThousands フラグを含む NumberStyles 値となり、これは解析される文字列にグループ記号、小数点区切り、負符号、および空白文字を含めることができる、または解析される文字列を指数表記での数値の文字列表現にできることを指定します。

また、解析メソッドは、解析する文字列内に現れる可能性のある特定の記号とパターンを定義する NumberFormatInfo オブジェクトを暗黙的または明示的に使用します。 NumberFormatInfo オブジェクトが指定されていない場合、既定値は現在のカルチャの NumberFormatInfo となります。 解析の詳細については、個々の解析メソッド (Int16.Parse(String)Int32.Parse(String, NumberStyles)Int64.Parse(String, IFormatProvider)Decimal.Parse(String, NumberStyles, IFormatProvider)Double.TryParse(String, Double)BigInteger.TryParse(String, NumberStyles, IFormatProvider, BigInteger) など) を参照してください。

次の例は、文字列の解析のカルチャに依存する性質を示しています。 これは、en-US、fr-FR、およびインバリアント カルチャの規則を使用して、3 桁区切りを含む文字列を解析しようとします。 コンマをグループ区切りとして含み、ピリオドを小数点区切りとして含む文字列は fr-FR カルチャでは解析に失敗し、空白をグループ区切りとして含み、コンマを小数点区切りとして含む文字列は、en-US カルチャとインバリアント カルチャでは解析に失敗します。

using System;
using System.Globalization;

public class ParseEx1
{
    public static void Main()
    {
        String[] values = { "1,034,562.91", "9 532 978,07" };
        String[] cultureNames = { "en-US", "fr-FR", "" };

        foreach (var value in values)
        {
            foreach (var cultureName in cultureNames)
            {
                CultureInfo culture = CultureInfo.CreateSpecificCulture(cultureName);
                String name = culture.Name == "" ? "Invariant" : culture.Name;
                try
                {
                    Decimal amount = Decimal.Parse(value, culture);
                    Console.WriteLine("'{0}' --> {1} ({2})", value, amount, name);
                }
                catch (FormatException)
                {
                    Console.WriteLine("'{0}': FormatException ({1})",
                                      value, name);
                }
            }
            Console.WriteLine();
        }
    }
}
// The example displays the following output:
//       '1,034,562.91' --> 1034562.91 (en-US)
//       '1,034,562.91': FormatException (fr-FR)
//       '1,034,562.91' --> 1034562.91 (Invariant)
//
//       '9 532 978,07': FormatException (en-US)
//       '9 532 978,07' --> 9532978.07 (fr-FR)
//       '9 532 978,07': FormatException (Invariant)

解析は通常、以下の 2 つのコンテキストで行われます。

  • ユーザー入力を数値に変換することを目的とした操作として。

  • 数値をラウンドトリップする、つまり以前に文字列としてシリアル化された数値を逆シリアル化することを目的とした操作として。

以降のセクションでは、これら 2 つの操作について詳しく説明します。

ユーザー文字列を解析する

ユーザーによる数値文字列入力を解析する際には、常にユーザーのカルチャ設定を反映する NumberFormatInfo オブジェクトのインスタンスを作成する必要があります。 ユーザー カスタマイズを反映する NumberFormatInfo オブジェクトのインスタンスを作成する方法については、「動的データ」セクションを参照してください。

次の例は、ユーザー カルチャ設定を反映する解析操作と反映しない解析操作の違いを示しています。 この場合、既定のシステム カルチャは en-US ですが、ユーザーはコントロール パネルの地域と言語で "," を小数点記号として、"." をグループ区切りとして定義しています。 通常、これらの記号は、既定の en-US カルチャでは逆の方法で使用されています。 ユーザーがユーザー設定を反映する文字列を入力し、その文字列がユーザー設定を反映 (オーバーライド) する NumberFormatInfo オブジェクトによって解析されると、解析操作は正しい結果を返します。 しかし、文字列が標準の en-US カルチャ設定を反映する NumberFormatInfo オブジェクトによって解析されると、これはコンマ記号を誤ってグループ区切りと見なして間違った結果を返します。

using System;
using System.Globalization;

public class ParseUserEx
{
    public static void Main()
    {
        CultureInfo stdCulture = CultureInfo.GetCultureInfo("en-US");
        CultureInfo custCulture = CultureInfo.CreateSpecificCulture("en-US");

        String value = "310,16";
        try
        {
            Console.WriteLine("{0} culture reflects user overrides: {1}",
                              stdCulture.Name, stdCulture.UseUserOverride);
            Decimal amount = Decimal.Parse(value, stdCulture);
            Console.WriteLine("'{0}' --> {1}", value, amount.ToString(CultureInfo.InvariantCulture));
        }
        catch (FormatException)
        {
            Console.WriteLine("Unable to parse '{0}'", value);
        }
        Console.WriteLine();

        try
        {
            Console.WriteLine("{0} culture reflects user overrides: {1}",
                              custCulture.Name, custCulture.UseUserOverride);
            Decimal amount = Decimal.Parse(value, custCulture);
            Console.WriteLine("'{0}' --> {1}", value, amount.ToString(CultureInfo.InvariantCulture));
        }
        catch (FormatException)
        {
            Console.WriteLine("Unable to parse '{0}'", value);
        }
    }
}
// The example displays the following output:
//       en-US culture reflects user overrides: False
//       '310,16' --> 31016
//
//       en-US culture reflects user overrides: True
//       '310,16' --> 310.16

数値データのシリアル化と逆シリアル化を行う

数値データを文字列形式にシリアル化し、後で逆シリアル化して解析する場合、文字列はインバリアント カルチャの規則を使用して生成および解析を行う必要があります。 書式設定と解析の操作は、特定のカルチャの規則を反映するべきではありません。 カルチャ固有設定を使用すると、データの移植性は厳しく制限され、データを正常に逆シリアル化できるのは、カルチャ固有設定がそのデータがシリアル化されたスレッドのものと同じスレッド上のみとなる可能性があります。 場合によっては、これはデータがシリアル化されたのと同じシステム上でも正常に逆シリアル化できない可能性があることを意味します。

次の例は、この原則に違反した場合に何が起こるかを示しています。 現在のスレッドが en-US カルチャのカルチャ固有設定を使用しているため、配列内の浮動小数値は文字列に変換されます。 データはその後、pt-BR カルチャのカルチャ固有設定を使用するスレッドによって解析されます。 この場合、各解析操作は成功しますが、データのラウンドトリップは成功せず、データの破損が発生します。 その他の場合としても、解析操作が失敗し、FormatException 例外がスローされる可能性があります。

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Threading;

public class ParsePersistedEx
{
    public static void Main()
    {
        CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
        PersistData();

        CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture("pt-BR");
        RestoreData();
    }

    private static void PersistData()
    {
        // Define an array of floating-point values.
        Double[] values = { 160325.972, 8631.16, 1.304e5, 98017554.385,
                          8.5938287084321676e94 };
        Console.WriteLine("Original values: ");
        foreach (var value in values)
            Console.WriteLine(value.ToString("R", CultureInfo.InvariantCulture));

        // Serialize an array of doubles to a file
        StreamWriter sw = new StreamWriter(@".\NumericData.bin");
        for (int ctr = 0; ctr < values.Length; ctr++)
        {
            sw.Write(values[ctr].ToString("R"));
            if (ctr < values.Length - 1) sw.Write("|");
        }
        sw.Close();
        Console.WriteLine();
    }

    private static void RestoreData()
    {
        // Deserialize the data
        StreamReader sr = new StreamReader(@".\NumericData.bin");
        String data = sr.ReadToEnd();
        sr.Close();

        String[] stringValues = data.Split('|');
        List<Double> newValueList = new List<Double>();

        foreach (var stringValue in stringValues)
        {
            try
            {
                newValueList.Add(Double.Parse(stringValue));
            }
            catch (FormatException)
            {
                newValueList.Add(Double.NaN);
            }
        }

        Console.WriteLine("Restored values:");
        foreach (var newValue in newValueList)
            Console.WriteLine(newValue.ToString("R", NumberFormatInfo.InvariantInfo));
    }
}
// The example displays the following output:
//       Original values:
//       160325.972
//       8631.16
//       130400
//       98017554.385
//       8.5938287084321671E+94
//
//       Restored values:
//       160325972
//       863116
//       130400
//       98017554385
//       8.5938287084321666E+110