我想把“3.5”这样的字符串解析为double。然而,

double.Parse("3.5") 

收益率为35和

double.Parse("3.5", System.Globalization.NumberStyles.AllowDecimalPoint) 

抛出一个FormatException。

现在我的计算机的区域设置为德语,其中逗号用作小数分隔符。它可能需要做一些事情,double.Parse()期望“3,5”作为输入,但我不确定。

如何解析包含十进制数字的字符串,该十进制数字可能是或可能不是我当前地区指定的格式?


当前回答

如果数值来自用户输入,我认为100%正确的转换是不可能的。例如,如果值是123.456,它可以是一个分组,也可以是一个小数点。如果你真的需要100%,你必须描述你的格式,如果不正确就抛出异常。

但我改进了JanW的代码,所以我们提前了一点,达到100%。背后的思想是,如果最后一个分隔符是groupseparator,它将更像是一个整数类型,而不是double类型。

添加的代码在GetDouble的第一个if中。

void Main()
{
    List<string> inputs = new List<string>() {
        "1.234.567,89",
        "1 234 567,89",
        "1 234 567.89",
        "1,234,567.89",
        "1234567,89",
        "1234567.89",
        "123456789",
        "123.456.789",
        "123,456,789,"
    };

    foreach(string input in inputs) {
        Console.WriteLine(GetDouble(input,0d));
    }

}

public static double GetDouble(string value, double defaultValue) {
    double result;
    string output;

    // Check if last seperator==groupSeperator
    string groupSep = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator;
    if (value.LastIndexOf(groupSep) + 4 == value.Count())
    {
        bool tryParse = double.TryParse(value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.CurrentCulture, out result);
        result = tryParse ? result : defaultValue;
    }
    else
    {
        // Unify string (no spaces, only . )
        output = value.Trim().Replace(" ", string.Empty).Replace(",", ".");

        // Split it on points
        string[] split = output.Split('.');

        if (split.Count() > 1)
        {
            // Take all parts except last
            output = string.Join(string.Empty, split.Take(split.Count()-1).ToArray());

            // Combine token parts with last part
            output = string.Format("{0}.{1}", output, split.Last());
        }
        // Parse double invariant
        result = double.Parse(output, System.Globalization.CultureInfo.InvariantCulture);
    }
    return result;
}

其他回答

下面的方法效率较低,但我使用这种逻辑。这只在小数点后有两位数字时有效。

double val;

if (temp.Text.Split('.').Length > 1)
{
    val = double.Parse(temp.Text.Split('.')[0]);

    if (temp.Text.Split('.')[1].Length == 1)
        val += (0.1 * double.Parse(temp.Text.Split('.')[1]));
    else
        val += (0.01 * double.Parse(temp.Text.Split('.')[1]));
}
else
    val = double.Parse(RR(temp.Text));
Double.Parse("3,5".Replace(',', '.'), CultureInfo.InvariantCulture)

在解析前将逗号替换为一个点。适用于以逗号作为小数分隔符的国家。考虑将用户输入限制为一个逗号或点(如果有必要)。

我正在开发一个。net Maui应用程序,可以在Windows、Mac、Android和iPhone上运行。我有3个双精度值,我解析和存储使用'。(如。“32.5”)在所有情况下:纬度、经度和海拔。我碰巧将Android和iPhone设置为西班牙语,并注意到Android会解析'。字符串很好。但是,iPhone拒绝正确解析它,除非我用','代替'.'。否则,结果总是一个巨大的数字。

我没有处理复杂的本地化问题,而是提出了一个简单的解决方案,即利用双数字的特定限制。

                     case "Lat":
                        waypoint.Lat = ParseDouble(xmlVal, 90);
                        break;
                     case "Lon":
                        waypoint.Lon = ParseDouble(xmlVal, 180);
                        break;
                     case "Alt":
                        waypoint.Alt = ParseDouble(xmlVal, 32000);

   public static double ParseDouble(string val, double limit)
   {
      double result;
      if (double.TryParse(val, out result))
      {
         if (Math.Abs(result) <= limit)
            return result;
         else if (double.TryParse(val.Replace('.', ','), out result))
         {
            if (Math.Abs(result) <= limit)
               return result;
         }
      }
      return 0;
   }

我也改进了@JanW的代码…

我需要它来格式化医疗器械的结果,他们还发送了“>1000”,“23.3e02”,“350E-02”和“NEGATIVE”。

private string FormatResult(string vResult)
{
  string output;
  string input = vResult;

  // Unify string (no spaces, only .)
  output = input.Trim().Replace(" ", "").Replace(",", ".");

  // Split it on points
  string[] split = output.Split('.');

  if (split.Count() > 1)
  {
    // Take all parts except last
    output = string.Join("", split.Take(split.Count() - 1).ToArray());

    // Combine token parts with last part
    output = string.Format("{0}.{1}", output, split.Last());
  }
  string sfirst = output.Substring(0, 1);

  try
  {
    if (sfirst == "<" || sfirst == ">")
    {
      output = output.Replace(sfirst, "");
      double res = Double.Parse(output);
      return String.Format("{1}{0:0.####}", res, sfirst);
    }
    else
    {
      double res = Double.Parse(output);
      return String.Format("{0:0.####}", res);
    }
  }
  catch
  {
    return output;
  }
}

我通常使用多区域性函数来解析用户输入,主要是因为如果某人习惯使用numpad,并且正在使用使用逗号作为小数分隔符的区域性,那么此人将使用numpad的点而不是逗号。

public static double GetDouble(string value, double defaultValue)
{
    double result;

    //Try parsing in the current culture
    if (!double.TryParse(value, System.Globalization.NumberStyles.Any, CultureInfo.CurrentCulture, out result) &&
        //Then try in US english
        !double.TryParse(value, System.Globalization.NumberStyles.Any, CultureInfo.GetCultureInfo("en-US"), out result) &&
        //Then in neutral language
        !double.TryParse(value, System.Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, out result))
    {
        result = defaultValue;
    }

    return result;
}

不过要注意,@nikie的评论是真的。我要为自己辩护的是,我在受控环境中使用这个函数,我知道文化可以是en-US、en-CA或fr-CA。我用这个函数是因为在法语中,我们用逗号作为小数分隔符,但任何在金融领域工作过的人都会在numpad上使用小数分隔符,但这是一个点,而不是一个逗号。因此,即使在fr-CA文化中,我也需要解析将以点作为小数分隔符的数字。