次の方法で共有


.NET での数値文字列の解析

すべての数値型には、数値の文字列形式を数値型に変換するために使用できる、 ParseTryParseの 2 つの静的解析メソッドがあります。 これらのメソッドを使用すると、「 標準の数値書式 指定文字列」および「 カスタム数値書式指定文字列」に記載されている書式指定文字列を使用して生成された文字列を解析できます。 既定では、 Parse メソッドと TryParse メソッドは、整数の 10 進数のみを含む文字列を整数値に正常に変換できます。 整数および小数部の 10 進数、グループ区切り記号、および小数点区切り記号を含む文字列を浮動小数点値に正常に変換できます。 Parse メソッドは、操作が失敗した場合に例外をスローしますが、TryParse メソッドはfalseを返します。

.NET 7 以降、.NET の数値型は、System.IParsable<TSelf>メソッドとIParsable<TSelf>.Parseメソッドを定義するIParsable<TSelf>.TryParse インターフェイスも実装します。

解析とフォーマットプロバイダー

通常、数値の文字列表現はカルチャによって異なります。 通貨記号、グループ (または 1000) の区切り記号、小数点の区切り記号など、数値文字列の要素はすべてカルチャによって異なります。 解析メソッドは、これらのカルチャ固有のバリエーションを認識する書式プロバイダーを暗黙的または明示的に使用します。 ParseまたはTryParse メソッドの呼び出しで書式プロバイダーが指定されていない場合は、現在のカルチャ (NumberFormatInfo プロパティによって返されるNumberFormatInfo.CurrentInfo オブジェクト) に関連付けられている書式プロバイダーが使用されます。

フォーマット プロバイダーは、 IFormatProvider 実装によって表されます。 このインターフェイスには、 GetFormat メソッドという 1 つのメンバーがあり、その単一パラメーターは、書式設定する型を表す Type オブジェクトです。 このメソッドは、書式設定情報を提供するオブジェクトを返します。 .NET では、数値文字列を解析するための次の 2 つの IFormatProvider 実装がサポートされています。

次の例では、配列内の各文字列を Double 値に変換しようとします。 最初に、英語 (米国) カルチャの規則を反映する書式プロバイダーを使用して文字列の解析を試みます。 この操作で FormatExceptionがスローされた場合、フランス語 (フランス) カルチャの規則を反映する書式プロバイダーを使用して文字列を解析しようとします。

using System;
using System.Globalization;

public class Example
{
   public static void Main()
   {
      string[] values = { "1,304.16", "$1,456.78", "1,094", "152",
                          "123,45 €", "1 304,16", "Ae9f" };
      double number;
      CultureInfo culture = null;

      foreach (string value in values) {
         try {
            culture = CultureInfo.CreateSpecificCulture("en-US");
            number = Double.Parse(value, culture);
            Console.WriteLine($"{culture.Name}: {value} --> {number}");
         }
         catch (FormatException) {
            Console.WriteLine($"{culture.Name}: Unable to parse '{value}'.");
            culture = CultureInfo.CreateSpecificCulture("fr-FR");
            try {
               number = Double.Parse(value, culture);
               Console.WriteLine($"{culture.Name}: {value} --> {number}");
            }
            catch (FormatException) {
               Console.WriteLine($"{culture.Name}: Unable to parse '{value}'.");
            }
         }
         Console.WriteLine();
      }
   }
}
// The example displays the following output:
//    en-US: 1,304.16 --> 1304.16
//
//    en-US: Unable to parse '$1,456.78'.
//    fr-FR: Unable to parse '$1,456.78'.
//
//    en-US: 1,094 --> 1094
//
//    en-US: 152 --> 152
//
//    en-US: Unable to parse '123,45 €'.
//    fr-FR: Unable to parse '123,45 €'.
//
//    en-US: Unable to parse '1 304,16'.
//    fr-FR: 1 304,16 --> 1304.16
//
//    en-US: Unable to parse 'Ae9f'.
//    fr-FR: Unable to parse 'Ae9f'.
Imports System.Globalization

Module Example
    Public Sub Main()
        Dim values() As String = {"1,304.16", "$1,456.78", "1,094", "152",
                                   "123,45 €", "1 304,16", "Ae9f"}
        Dim number As Double
        Dim culture As CultureInfo = Nothing

        For Each value As String In values
            Try
                culture = CultureInfo.CreateSpecificCulture("en-US")
                number = Double.Parse(value, culture)
                Console.WriteLine("{0}: {1} --> {2}", culture.Name, value, number)
            Catch e As FormatException
                Console.WriteLine("{0}: Unable to parse '{1}'.",
                                  culture.Name, value)
                culture = CultureInfo.CreateSpecificCulture("fr-FR")
                Try
                    number = Double.Parse(value, culture)
                    Console.WriteLine("{0}: {1} --> {2}", culture.Name, value, number)
                Catch ex As FormatException
                    Console.WriteLine("{0}: Unable to parse '{1}'.",
                                      culture.Name, value)
                End Try
            End Try
            Console.WriteLine()
        Next
    End Sub
End Module
' The example displays the following output:
'    en-US: 1,304.16 --> 1304.16
'    
'    en-US: Unable to parse '$1,456.78'.
'    fr-FR: Unable to parse '$1,456.78'.
'    
'    en-US: 1,094 --> 1094
'    
'    en-US: 152 --> 152
'    
'    en-US: Unable to parse '123,45 €'.
'    fr-FR: Unable to parse '123,45 €'.
'    
'    en-US: Unable to parse '1 304,16'.
'    fr-FR: 1 304,16 --> 1304.16
'    
'    en-US: Unable to parse 'Ae9f'.
'    fr-FR: Unable to parse 'Ae9f'.

解析値と NumberStyles の値

解析操作で処理できるスタイル要素 (空白、グループ区切り記号、小数点区切り記号など) は、 NumberStyles 列挙値によって定義されます。 既定では、整数値を表す文字列は、 NumberStyles.Integer 値を使用して解析されます。この値では、数字、先頭と末尾の空白、および先頭の符号のみが許可されます。 浮動小数点値を表す文字列は、 NumberStyles.Float 値と NumberStyles.AllowThousands 値の組み合わせを使用して解析されます。この複合スタイルでは、先頭と末尾の空白、先頭の記号、小数点、グループ区切り記号、指数と共に 10 進数を使用できます。 Parse型のパラメーターを含むTryParseまたはNumberStyles メソッドのオーバーロードを呼び出し、1 つ以上のNumberStyles フラグを設定することで、解析操作を成功させるために文字列に存在できるスタイル要素を制御できます。

たとえば、グループ区切り記号を含む文字列は、Int32 メソッドを使用してInt32.Parse(String)値に変換することはできません。 ただし、次の例に示すように、 NumberStyles.AllowThousands フラグを使用すると変換は成功します。

using System;
using System.Globalization;

public class Example
{
   public static void Main()
   {
      string value = "1,304";
      int number;
      IFormatProvider provider = CultureInfo.CreateSpecificCulture("en-US");
      if (Int32.TryParse(value, out number))
         Console.WriteLine($"{value} --> {number}");
      else
         Console.WriteLine($"Unable to convert '{value}'");

      if (Int32.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands,
                        provider, out number))
         Console.WriteLine($"{value} --> {number}");
      else
         Console.WriteLine($"Unable to convert '{value}'");
   }
}
// The example displays the following output:
//       Unable to convert '1,304'
//       1,304 --> 1304
Imports System.Globalization

Module Example
    Public Sub Main()
        Dim value As String = "1,304"
        Dim number As Integer
        Dim provider As IFormatProvider = CultureInfo.CreateSpecificCulture("en-US")
        If Int32.TryParse(value, number) Then
            Console.WriteLine("{0} --> {1}", value, number)
        Else
            Console.WriteLine("Unable to convert '{0}'", value)
        End If

        If Int32.TryParse(value, NumberStyles.Integer Or NumberStyles.AllowThousands,
                          provider, number) Then
            Console.WriteLine("{0} --> {1}", value, number)
        Else
            Console.WriteLine("Unable to convert '{0}'", value)
        End If
    End Sub
End Module
' The example displays the following output:
'       Unable to convert '1,304'
'       1,304 --> 1304

Warnung

解析操作では、常に特定のカルチャの書式設定規則が使用されます。 CultureInfoまたはNumberFormatInfoオブジェクトを渡してカルチャを指定しない場合は、現在のスレッドに関連付けられているカルチャが使用されます。

次の表に、 NumberStyles 列挙体のメンバーを示し、解析操作に与える影響について説明します。

"NumberStyles" 値 解析する文字列に対する影響
NumberStyles.None 数字のみが許可されます。
NumberStyles.AllowDecimalPoint 小数点区切り記号と小数部の数字を使用できます。 整数値の場合、小数部の数字として使用できるのは 0 のみです。 有効な小数点区切り記号は、 NumberFormatInfo.NumberDecimalSeparator または NumberFormatInfo.CurrencyDecimalSeparator プロパティによって決まります。
NumberStyles.AllowExponent "e" または "E" 文字は、指数表記を示すために使用できます。 詳細については、NumberStylesを参照してください。
NumberStyles.AllowLeadingWhite 先頭の空白文字は許可されています。
NumberStyles.AllowTrailingWhite 末尾の空白は許可されます。
NumberStyles.AllowLeadingSign 正符号または負符号は、数字の前に置くことができます。
NumberStyles.AllowTrailingSign 正符号または負符号は、数字の後に続く場合があります。
NumberStyles.AllowParentheses 括弧を使用して負の値を示すことができます。
NumberStyles.AllowThousands グループ区切り記号を使用できます。 グループ区切り文字は、 NumberFormatInfo.NumberGroupSeparator または NumberFormatInfo.CurrencyGroupSeparator プロパティによって決まります。
NumberStyles.AllowCurrencySymbol 通貨記号を使用できます。 通貨記号は、 NumberFormatInfo.CurrencySymbol プロパティによって定義されます。
NumberStyles.AllowHexSpecifier 解析される文字列は、16 進数として解釈されます。 これには、0 から 9 の 16 進数、A から F、および a から f を含めることができます。 このフラグは、整数値の解析にのみ使用できます。
NumberStyles.AllowBinarySpecifier 解析される文字列は、2 進数として解釈されます。 2 進数の 0 と 1 を含めることができます。 このフラグは、整数値の解析にのみ使用できます。

さらに、 NumberStyles 列挙には、複数の NumberStyles フラグを含む次の複合スタイルが用意されています。

複合型 NumberStyles の値 メンバーを含む
NumberStyles.Integer NumberStyles.AllowLeadingWhiteNumberStyles.AllowTrailingWhite、およびNumberStyles.AllowLeadingSignのスタイルが含まれます。 これは、整数値の解析に使用される既定のスタイルです。
NumberStyles.Number NumberStyles.AllowLeadingWhiteNumberStyles.AllowTrailingWhiteNumberStyles.AllowLeadingSignNumberStyles.AllowTrailingSignNumberStyles.AllowDecimalPoint、およびNumberStyles.AllowThousandsのスタイルが含まれます。
NumberStyles.Float NumberStyles.AllowLeadingWhiteNumberStyles.AllowTrailingWhiteNumberStyles.AllowLeadingSignNumberStyles.AllowDecimalPoint、およびNumberStyles.AllowExponentのスタイルが含まれます。
NumberStyles.Currency NumberStyles.AllowExponentNumberStyles.AllowHexSpecifierを除くすべてのスタイルが含まれます。
NumberStyles.Any NumberStyles.AllowHexSpecifierを除くすべてのスタイルが含まれます。
NumberStyles.HexNumber NumberStyles.AllowLeadingWhiteNumberStyles.AllowTrailingWhite、およびNumberStyles.AllowHexSpecifierのスタイルが含まれます。
NumberStyles.BinaryNumber NumberStyles.AllowLeadingWhiteNumberStyles.AllowTrailingWhite、およびNumberStyles.AllowBinarySpecifierのスタイルが含まれます。

バイナリおよび 16 進数の BigIntegers の解析

BigIntegerフラグまたはAllowHexSpecifier フラグを使用してAllowBinarySpecifierを解析する場合、入力文字列は文字列の正確な長さの 16 進数/2 進数として解釈されます。 たとえば、 "11" をバイナリ BigInteger として解析すると、 -1が生成されます。これは、 11 が厳密に 2 桁の符号付き 2 の補数値として解釈されるためです。 肯定的な結果が必要な場合は、0として解析される"011"など、先頭の3を追加します。

解析とUnicode数字

Unicode 標準では、さまざまな書き込みシステムの数字のコード ポイントが定義されています。 たとえば、U+0030 から U+0039 までのコード ポイントは、基本的なラテン数字 0 から 9 を表し、U+09E6 から U+09EF までのコード ポイントはバングラの数字 0 から 9 を表し、U+FF10 から U+FF19 までのコード ポイントは完全な数字 0 から 9 を表します。 ただし、解析方法で認識される数字は、U+0030 から U+0039 までのコード ポイントを持つ基本的なラテン数字 0 から 9 のみです。 数値解析メソッドに他の数字を含む文字列が渡された場合、メソッドは FormatExceptionをスローします。

次の例では、 Int32.Parse メソッドを使用して、異なる書き込みシステムの数字で構成される文字列を解析します。 この例の出力が示すように、基本的なラテン数字の解析は成功しますが、Fullwidth、Arabic-Indic、Bangla の各桁を解析しようとすると失敗します。

using System;

public class Example
{
   public static void Main()
   {
      string value;
      // Define a string of basic Latin digits 1-5.
      value = "\u0031\u0032\u0033\u0034\u0035";
      ParseDigits(value);

      // Define a string of Fullwidth digits 1-5.
      value = "\uFF11\uFF12\uFF13\uFF14\uFF15";
      ParseDigits(value);

      // Define a string of Arabic-Indic digits 1-5.
      value = "\u0661\u0662\u0663\u0664\u0665";
      ParseDigits(value);

      // Define a string of Bangla digits 1-5.
      value = "\u09e7\u09e8\u09e9\u09ea\u09eb";
      ParseDigits(value);
   }

   static void ParseDigits(string value)
   {
      try {
         int number = Int32.Parse(value);
         Console.WriteLine($"'{value}' --> {number}");
      }
      catch (FormatException) {
         Console.WriteLine($"Unable to parse '{value}'.");
      }
   }
}
// The example displays the following output:
//       '12345' --> 12345
//       Unable to parse '12345'.
//       Unable to parse '١٢٣٤٥'.
//       Unable to parse '১২৩৪৫'.
Module Example
    Public Sub Main()
        Dim value As String
        ' Define a string of basic Latin digits 1-5.
        value = ChrW(&h31) + ChrW(&h32) + ChrW(&h33) + ChrW(&h34) + ChrW(&h35)
        ParseDigits(value)

        ' Define a string of Fullwidth digits 1-5.
        value = ChrW(&hff11) + ChrW(&hff12) + ChrW(&hff13) + ChrW(&hff14) + ChrW(&hff15)
        ParseDigits(value)

        ' Define a string of Arabic-Indic digits 1-5.
        value = ChrW(&h661) + ChrW(&h662) + ChrW(&h663) + ChrW(&h664) + ChrW(&h665)
        ParseDigits(value)

        ' Define a string of Bangla digits 1-5.
        value = ChrW(&h09e7) + ChrW(&h09e8) + ChrW(&h09e9) + ChrW(&h09ea) + ChrW(&h09eb)
        ParseDigits(value)
    End Sub

    Sub ParseDigits(value As String)
        Try
            Dim number As Integer = Int32.Parse(value)
            Console.WriteLine("'{0}' --> {1}", value, number)
        Catch e As FormatException
            Console.WriteLine("Unable to parse '{0}'.", value)
        End Try
    End Sub
End Module
' The example displays the following output:
'       '12345' --> 12345
'       Unable to parse '12345'.
'       Unable to parse '١٢٣٤٥'.
'       Unable to parse '১২৩৪৫'.

こちらも参照ください