通过


在 .NET 中分析数值字符串

所有数值类型都有两种静态分析方法, ParseTryParse可用于将数字的字符串表示形式转换为数值类型。 这些方法使你能够分析使用 标准数字格式字符串自定义数字格式字符串中记录的格式字符串生成的字符串。 默认情况下, ParseTryParse 方法可以成功将包含整型十进制数字的字符串转换为整数值。 它们可以成功将包含整数和小数位数、组分隔符和小数分隔符的字符串转换为浮点值。 如果操作失败,该方法 Parse 将引发异常,而 TryParse 该方法返回 false

注释

从 .NET 7 开始,.NET 中的数值类型也实现 System.IParsable<TSelf> 接口,该接口定义 IParsable<TSelf>.ParseIParsable<TSelf>.TryParse 方法。

解析和格式化提供程序

通常,数字值的字符串表示形式因文化而异。 数字字符串的元素(如货币符号、组(或千位)分隔符和小数点分隔符)都因文化而异。 解析方法可以通过隐式或显式方式使用能够识别这些地区特定变体的格式提供程序。 如果在调用 ParseTryParse 方法时未指定格式提供程序,则会使用与当前文化相关联的格式提供程序(即 NumberFormatInfo.CurrentInfo 属性返回的 NumberFormatInfo 对象)。

格式提供程序由 IFormatProvider 实现表示。 此接口具有单个成员( GetFormat 该方法),该方法的单个参数是表示 Type 要格式化的类型的对象。 此方法返回提供格式设置信息的对象。 .NET 支持以下两 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.FloatNumberStyles.AllowThousands 这两个值的组合进行解析;这种复合样式允许包含十进制数字,以及前导和尾随的空格、前导符号、小数分隔符、组分隔符和指数。 通过调用包含类型NumberStyles参数的ParseTryParse方法的重载,并设置一个或多个NumberStyles标志,可以控制字符串中可能存在的样式元素,以便解析操作成功。

例如,包含组分隔符的字符串无法使用该方法转换为 Int32Int32.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

警告

解析操作始终使用特定文化的格式约定。 如果不通过传递 CultureInfoNumberFormatInfo 对象来指定区域性,则使用与当前线程关联的区域性。

下表列出了枚举的成员 NumberStyles ,并描述了它们在分析操作上的效果。

NumberStyles 值 对要分析的字符串的影响
NumberStyles.None 仅允许数字数字。
NumberStyles.AllowDecimalPoint 允许使用小数分隔符和小数位数。 对于整数值,仅允许将零作为小数位数。 有效的小数分隔符由 NumberFormatInfo.NumberDecimalSeparatorNumberFormatInfo.CurrencyDecimalSeparator 属性确定。
NumberStyles.AllowExponent “e”或“E”字符可用于指示指数表示法。 有关详细信息,请参阅 NumberStyles
NumberStyles.AllowLeadingWhite 允许前导空格。
NumberStyles.AllowTrailingWhite 允许尾随空格。
NumberStyles.AllowLeadingSign 正数或负号可以位于数字数字之前。
NumberStyles.AllowTrailingSign 正号或负号可以跟在数字后面。
NumberStyles.AllowParentheses 括号可用于指示负值。
NumberStyles.AllowThousands 允许组分隔符。 组分隔符由 NumberFormatInfo.NumberGroupSeparatorNumberFormatInfo.CurrencyGroupSeparator 属性确定。
NumberStyles.AllowCurrencySymbol 允许使用货币符号。 货币符号由 NumberFormatInfo.CurrencySymbol 属性定义。
NumberStyles.AllowHexSpecifier 要分析的字符串被解释为十六进制数。 它可以包括十六进制数字 0-9、A-F 和 a-f。 此标志只能用于分析整数值。
NumberStyles.AllowBinarySpecifier 要分析的字符串被解释为二进制数。 它可以包括二进制数字 0 和 1。 此标志只能用于分析整数值。

此外, NumberStyles 枚举还提供以下复合样式,其中包括多个 NumberStyles 标志。

复合 NumberStyles 值 包括成员
NumberStyles.Integer 包括NumberStyles.AllowLeadingWhiteNumberStyles.AllowTrailingWhiteNumberStyles.AllowLeadingSign样式。 这是用于分析整数值的默认样式。
NumberStyles.Number NumberStyles.AllowLeadingWhite包括、NumberStyles.AllowTrailingWhiteNumberStyles.AllowLeadingSignNumberStyles.AllowTrailingSign、和NumberStyles.AllowDecimalPointNumberStyles.AllowThousands样式。
NumberStyles.Float 包括NumberStyles.AllowLeadingWhiteNumberStyles.AllowTrailingWhiteNumberStyles.AllowLeadingSignNumberStyles.AllowDecimalPointNumberStyles.AllowExponent样式。
NumberStyles.Currency 包括所有样式,除了NumberStyles.AllowExponentNumberStyles.AllowHexSpecifier
NumberStyles.Any 包括所有样式, 但 NumberStyles.AllowHexSpecifier 除外。
NumberStyles.HexNumber 包括NumberStyles.AllowLeadingWhiteNumberStyles.AllowTrailingWhiteNumberStyles.AllowHexSpecifier样式。
NumberStyles.BinaryNumber NumberStyles.AllowLeadingWhiteNumberStyles.AllowTrailingWhiteNumberStyles.AllowBinarySpecifier样式包括在内。

解析二进制和十六进制的大数整数

在使用BigIntegerAllowHexSpecifier标志解析AllowBinarySpecifier时,将输入字符串按其长度精确解释为十六进制或二进制数。 例如,将 "11" 解析为二进制 BigInteger 会得到 -1,因为这是将 11 解释为准确由两位二进制数字表示的有符号补码值。 如果期望获得积极的结果,请添加前导0,例如"011"会被解析为3

分析和 Unicode 数字

Unicode 标准定义各种写入系统中数字的代码点。 例如,从 U+0030 到 U+0039 的代码点表示基本拉丁数字 0 到 9,从 U+09E6 到 U+09EF 的代码点表示孟加拉语数字 0 到 9,从 U+FF10 到 U+FF19 的代码点表示全形数字 0 到 9。 但是,分析方法识别的唯一数字数字是基本拉丁数字 0-9,代码点从 U+0030 到 U+0039。 如果数值分析方法传递了包含任何其他数字的字符串,该方法将引发一个 FormatException

以下示例使用 Int32.Parse 该方法分析由不同写入系统中的数字组成的字符串。 如示例输出所示,尝试分析基本拉丁数字成功,但尝试分析 Fullwidth、阿拉伯语-Indic 和孟加拉语数字失败。

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 '১২৩৪৫'.

另见