首页 文章

如何将带小数点的字符串解析为double?

提问于
浏览
187

我想将像 "3.5" 这样的字符串解析为double . 然而,

double.Parse("3.5")

收益35和

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

扔了 FormatException .

现在我的计算机的语言环境设置为德语,其中逗号用作小数分隔符 . 它可能需要对此做一些事情并期待 "3,5" 作为输入,但我不确定 .

如何解析包含十进制数的字符串,该十进制数可能是也可能不是我当前语言环境中指定的格式?

17 回答

  • 15
    double.Parse("3.5", CultureInfo.InvariantCulture)
    
  • 17

    我不想在所有解析中指定语言环境,而是更喜欢设置应用程序范围的语言环境,但如果字符串格式在应用程序中不一致,则可能无效 .

    CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("pt-PT");
    CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("pt-PT");
    

    在应用程序开始时定义它将使所有双解析期望逗号作为小数分隔符 . 您可以设置适当的区域设置,以便小数和千位分隔符适合您要解析的字符串 .

  • 64

    我通常使用多文化函数来解析用户输入,主要是因为如果有人习惯于小键盘并使用使用逗号作为小数分隔符的文化,那么该人将使用小键盘的点而不是逗号 .

    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;
    }
    

    请注意,@ nicie评论是真的 . 为了我的辩护,我在受控环境中使用此功能,我知道文化可以是en-US,en-CA或fr-CA . 我使用这个函数是因为在法语中,我们使用逗号作为小数分隔符,但是任何曾在金融界工作过的人都会在小键盘上使用小数分隔符,但这是一个点,而不是逗号 . 因此,即使在fr-CA文化中,我也需要解析具有小数分隔符的数字 .

  • 2

    我不能写评论,所以我写在这里:

    double.Parse("3.5", CultureInfo.InvariantCulture) 不是一个好主意,因为在加拿大我们写的是3,5而不是3.5,这个函数给我们35个作为结果 .

    我在电脑上测试了两个:

    double.Parse("3.5", CultureInfo.InvariantCulture) --> 3.5 OK
    double.Parse("3,5", CultureInfo.InvariantCulture) --> 35 not OK
    

    这是 Pierre-Alain Vigeant 提到的正确方法

    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;
    }
    
  • 9

    诀窍是使用不变的文化,在所有文化中解析点 .

    double.Parse("3.5", System.Globalization.NumberStyles.AllowDecimalPoint, System.Globalization.NumberFormatInfo.InvariantInfo);
    
  • 0
    Double.Parse("3,5".Replace(',', '.'), CultureInfo.InvariantCulture)
    

    在解析之前用逗号替换逗号 . 在逗号为小数分隔符的国家/地区中很有用 . 考虑将用户输入(如有必要)限制为一个逗号或点 .

  • 0

    看,上面的每个答案建议用常量字符串写一个字符串替换只能是错误的 . 为什么?因为您不尊重Windows的区域设置! Windows确保用户可以自由设置他/她想要的任何分隔符 . 他/她可以打开控制面板,进入区域面板,点击高级并随时更改角色 . 即使在你的程序运行期间 . 想一想 . 一个好的解决方案必须要注意这一点 .

    所以,首先你必须问自己,这个数字来自哪里,你要解析 . 如果它来自.NET Framework中的输入没问题,因为它将采用相同的格式 . 但也许它来自外部,可能来自外部服务器,也许来自只支持字符串属性的旧数据库 . 在那里,数据库管理员应该给出一个规则,以这种格式存储数字 . 如果你知道它将是一个美国格式的美国数据库,你可以使用这段代码:

    CultureInfo usCulture = new CultureInfo("en-US");
    NumberFormatInfo dbNumberFormat = usCulture.NumberFormat;
    decimal number = decimal.Parse(db.numberString, dbNumberFormat);
    

    这将在世界任何地方都能正常工作 . 请不要使用'Convert.ToXxxx' . “转换”类仅被视为任何方向转换的基础 . 此外:您也可以使用DateTimes的类似机制 .

  • 363
    string testString1 = "2,457";
    string testString2 = "2.457";    
    double testNum = 0.5;
    char decimalSepparator;
    decimalSepparator = testNum.ToString()[1];
    
    Console.WriteLine(double.Parse(testString1.Replace('.', decimalSepparator).Replace(',', decimalSepparator)));
    Console.WriteLine(double.Parse(testString2.Replace('.', decimalSepparator).Replace(',', decimalSepparator)));
    
  • -1

    以下代码可以在任何方案中完成工作 . 它有点解析 .

    List<string> inputs = new List<string>()
    {
        "1.234.567,89",
        "1 234 567,89",
        "1 234 567.89",
        "1,234,567.89",
        "123456789",
        "1234567,89",
        "1234567.89",
    };
    string output;
    
    foreach (string input in inputs)
    {
        // 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());
        }
    
        // Parse double invariant
        double d = double.Parse(output, CultureInfo.InvariantCulture);
        Console.WriteLine(d);
    }
    
  • 9

    我认为如果值来自用户输入,则无法100%正确转换 . 例如如果值为123.456,则可以是分组,也可以是小数点 . 如果你真的需要100%,你必须描述你的格式并在不正确的情况下抛出异常 .

    但是我改进了JanW的代码,所以我们更加领先于100% . 背后的想法是,如果最后一个分隔符是groupSeperator,这将是一个整数类型,而不是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;
    }
    
  • 1

    没有指定要查找的小数点分隔符很困难,但是如果你这样做,这就是我正在使用的:

    public static double Parse(string str, char decimalSep)
        {
            string s = GetInvariantParseString(str, decimalSep);
            return double.Parse(s, System.Globalization.CultureInfo.InvariantCulture);
        }
    
        public static bool TryParse(string str, char decimalSep, out double result)
        {
            // NumberStyles.Float | NumberStyles.AllowThousands got from Reflector
            return double.TryParse(GetInvariantParseString(str, decimalSep), NumberStyles.Float | NumberStyles.AllowThousands, System.Globalization.CultureInfo.InvariantCulture, out result);
        }
    
        private static string GetInvariantParseString(string str, char decimalSep)
        {
            str = str.Replace(" ", "");
    
            if (decimalSep != '.')
                str = SwapChar(str, decimalSep, '.');
    
            return str;
        }
        public static string SwapChar(string value, char from, char to)
        {
            if (value == null)
                throw new ArgumentNullException("value");
    
            StringBuilder builder = new StringBuilder();
    
            foreach (var item in value)
            {
                char c = item;
                if (c == from)
                    c = to;
                else if (c == to)
                    c = from;
    
                builder.Append(c);
            }
            return builder.ToString();
        }
    
        private static void ParseTestErr(string p, char p_2)
        {
            double res;
            bool b = TryParse(p, p_2, out res);
            if (b)
                throw new Exception();
        }
    
        private static void ParseTest(double p, string p_2, char p_3)
        {
            double d = Parse(p_2, p_3);
            if (d != p)
                throw new Exception();
        }
    
        static void Main(string[] args)
        {
            ParseTest(100100100.100, "100.100.100,100", ',');
            ParseTest(100100100.100, "100,100,100.100", '.');
            ParseTest(100100100100, "100.100.100.100", ',');
            ParseTest(100100100100, "100,100,100,100", '.');
            ParseTestErr("100,100,100,100", ',');
            ParseTestErr("100.100.100.100", '.');
            ParseTest(100100100100, "100 100 100 100.0", '.');
            ParseTest(100100100.100, "100 100 100.100", '.');
            ParseTest(100100100.100, "100 100 100,100", ',');
            ParseTest(100100100100, "100 100 100,100", '.');
            ParseTest(1234567.89, "1.234.567,89", ',');    
            ParseTest(1234567.89, "1 234 567,89", ',');    
            ParseTest(1234567.89, "1 234 567.89",     '.');
            ParseTest(1234567.89, "1,234,567.89",    '.');
            ParseTest(1234567.89, "1234567,89",     ',');
            ParseTest(1234567.89, "1234567.89",  '.');
            ParseTest(123456789, "123456789", '.');
            ParseTest(123456789, "123456789", ',');
            ParseTest(123456789, "123.456.789", ',');
            ParseTest(1234567890, "1.234.567.890", ',');
        }
    

    这适用于任何文化 . 它正确地无法解析具有多个小数分隔符的字符串,这与替换而不是交换的实现不同 .

  • 1

    我改进了@JanW的代码也是......

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

    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;
      }
    }
    
  • 0
    var doublePattern = @"(?<integer>[0-9]+)(?:\,|\.)(?<fraction>[0-9]+)";
            var sourceDoubleString = "03444,44426";
            var match = Regex.Match(sourceDoubleString, doublePattern);
    
            var doubleResult = match.Success ? double.Parse(match.Groups["integer"].Value) + (match.Groups["fraction"].Value == null ? 0 : double.Parse(match.Groups["fraction"].Value) / Math.Pow(10, match.Groups["fraction"].Value.Length)): 0;
            Console.WriteLine("Double of string '{0}' is {1}", sourceDoubleString, doubleResult);
    
  • -2
    System.Globalization.CultureInfo ci = System.Globalization.CultureInfo.CurrentCulture;
    
    string _pos = dblstr.Replace(".",
        ci.NumberFormat.NumberDecimalSeparator).Replace(",",
            ci.NumberFormat.NumberDecimalSeparator);
    
    double _dbl = double.Parse(_pos);
    
  • -3

    我认为这是最好的答案:

    public static double StringToDouble(string toDouble)
    {
        toDouble = toDouble.Replace(",", "."); //Replace every comma with dot
    
        //Count dots in toDouble, and if there is more than one dot, throw an exception.
        //Value such as "123.123.123" can't be converted to double
        int dotCount = 0;
        foreach (char c in toDouble) if (c == '.') dotCount++; //Increments dotCount for each dot in toDouble
        if (dotCount > 1) throw new Exception(); //If in toDouble is more than one dot, it means that toCount is not a double
    
        string left = toDouble.Split('.')[0]; //Everything before the dot
        string right = toDouble.Split('.')[1]; //Everything after the dot
    
        int iLeft = int.Parse(left); //Convert strings to ints
        int iRight = int.Parse(right);
    
        //We must use Math.Pow() instead of ^
        double d = iLeft + (iRight * Math.Pow(10, -(right.Length)));
        return d;
    }
    
  • -2

    以下效率较低,但我使用这种逻辑 . 仅当小数点后有两位数时才有效 .

    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));
    
  • 0

    将数字乘以然后除以之前相乘的数字 .

    例如,

    perc = double.Parse("3.555)*1000;
    result = perc/1000
    

相关问题