【问题标题】:Parse strings to double with comma and point用逗号和点解析字符串以加倍
【发布时间】:2012-07-19 12:03:20
【问题描述】:

我正在尝试编写一个函数,它基本上将字符串数组转换为字符串数组,其中数组中的所有双精度数都舍入到我设置的小数位数。数组中也可以有根本不是双精度值的字符串。

string[,] values = new string[1, 3];

values[0, 0] = "hello";
values[0, 1] = "0.123";
values[0, 2] = "0,123";

int decimalPlaces = 2;

double tmp;
string format = "F" + decimalPlaces.ToString();
IFormatProvider provider = CultureInfo.InvariantCulture;
for (int i = 0; i < values.GetLength(0); i++)
{
    for (int j = 0; j < values.GetLength(1); j++)
    {
        if (double.TryParse(values[i, j], out tmp))
        {
            values[i, j] = tmp.ToString(format, provider);
        }
    }
}

Console.ReadLine();

结果必须是: "hello" , "0.12", "0.12" 但它是 "hello", "123.00", "0.12" 会以错误的方式处理逗号。有没有人为此提供简单有效的解决方案?

【问题讨论】:

  • 正如 hultqvist 在评论中指出的那样,如果当前文化使用点“。”,则当前接受的答案会中断。作为小数点!那么,您介意将接受的答案更改为投票最多的答案吗?

标签: c#


【解决方案1】:

同时处理 , 和 .作为小数点,您不仅必须将一个替换为另一个,而且还要确保使用的文化解析将其解释为小数点。

text = text.Replace(',', '.');
return double.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out value);

【讨论】:

  • 这可能会导致千位分隔符出现一些问题。
  • @Retic 实际上,一种文化的千位分隔符是另一种文化的小数分隔符。
  • @hultqvist 我认为在拉丁西班牙文化中,“1,000”将被替换为“1”。预计为“1000”。
  • @alan-mattano 此解决方案适用于特定问题。没有针对所有文化的单一解决方案,您必须首先检测正在使用哪种文化,然后相应地选择算法。
【解决方案2】:

你不需要替换逗号和点..

我也遇到过同样的问题。原因很简单,转换文化在解释逗号或点时起着很大的作用。我使用的德国文化中,逗号区分分数,而在其他地方,点就可以了。

这里我做了一个完整的例子来说明区别。

string[] doubleStrings = {"hello", "0.123", "0,123"};
double localCultreResult;
foreach (var doubleString in doubleStrings)
{
    double.TryParse(doubleString, NumberStyles.Any, CultureInfo.CurrentCulture, out localCultreResult);
    Console.WriteLine(string.Format("Local culture results for the parsing of {0} is {1}", doubleString, localCultreResult));
}

double invariantCultureResult;
foreach (var doubleString in doubleStrings)
{
    double.TryParse(doubleString, NumberStyles.Any, CultureInfo.InvariantCulture, out invariantCultureResult);
    Console.WriteLine(string.Format("Invariant culture results for the parsing of {0} is {1}", doubleString, invariantCultureResult));
}

结果如下:

玩弄文化,你会得到你需要的结果。

【讨论】:

  • 我在几台具有不同文化设置的 PC 上尝试了这个解决方案。它没有按预期工作。我稍后会发布另一个解决方案。
  • 我试过这个,但它对我不起作用。请查看链接中的图片。 CurrentCulture 参数是德语。 imgur.com/QvtPt7S
  • 这应该是公认的答案。如果您需要更多限制,您也可以使用NumberStyles.AllowDecimalPoint 作为第二个参数。这对我来说很好!
【解决方案3】:

您希望将点 (.) 视为逗号 (,)。所以,替换

if (double.TryParse(values[i, j], out tmp))

if (double.TryParse(values[i, j].Replace('.', ','), out tmp))

【讨论】:

  • 解析时需要指定文化,否则只有在当前文化使用“,”作为小数点的情况下才有效。
  • 对。感谢您的警告。
  • 我知道线程已经死了,但我会用replace(char, char) 替换Replace(string, string) 以获得更好的性能.....
  • 替换是个坏主意,因为在 PC 上使用另一种文化设置的应用程序会失败...我稍后会写更好的修复程序。
【解决方案4】:

问题是您(或系统)无法区分小数分隔符和千位分隔符,因为它们可以是逗号或点。例如:

在我的文化中,

1.123 是 1000 以上数字的正常表示法;而

1,123 是接近 1 的数字。

使用不变文化默认使用点作为小数分隔符。一般来说,您应该确保在所有系统上使用相同的常量文化(例如不变文化)编写所有数字。

如果您确定您的数字除了逗号或点作为小数点分隔符(即没有千位分隔符)之外不包含任何其他内容,我会 String.Replace() 带点的逗号,然后像您一样完成其余的操作。

否则,您将很难在不了解文化的情况下编写能够区分 1.1231,123 的东西。

【讨论】:

  • 同意,对我来说这是最合乎逻辑的解决方案。您还可以检查字符串是否包含“,”或“。”但是这些解决方案中的任何一个都应该没问题。
  • “...在所有系统上...”远远超出了我的控制范围。
【解决方案5】:

制作两种静态文化,一种用于逗号,一种用于点。

    var commaCulture = new CultureInfo("en")
    {
        NumberFormat =
        {
            NumberDecimalSeparator = ","
        }
    };

    var pointCulture = new CultureInfo("en")
    {
        NumberFormat =
        {
            NumberDecimalSeparator = "."
        }
    };

然后根据输入分别使用每一个(使用函数):

    public double ConvertToDouble(string input)
    {
        input = input.Trim();

        if (input == "0") {
            return 0;
        }

        if (input.Contains(",") && input.Split(',').Length == 2)
        {
            return Convert.ToDouble(input, commaCulture);
        }

        if (input.Contains(".") && input.Split('.').Length == 2)
        {
            return Convert.ToDouble(input, pointCulture);
        }

        throw new Exception("Invalid input!");
    }

然后循环遍历你的数组

    var strings = new List<string> {"0,12", "0.122", "1,23", "00,0", "0.00", "12.5000", "0.002", "0,001"};
    var doubles = new List<double>();

    foreach (var value in strings) {
        doubles.Add(ConvertToDouble(value));
    }

即使宿主环境和文化发生变化,这也应该有效。

【讨论】:

  • 不是真的,如果你有 1,000,000.20 它会失败
【解决方案6】:

简单使用:

double.Parse("3.5", CultureInfo.InvariantCulture)

【讨论】:

【解决方案7】:

使用这个 double.TryParse 的重载来指定允许的格式:

Double.TryParse Method (String, NumberStyles, IFormatProvider, Double%)

默认情况下,double.TryParse 将根据当前的文化特定格式进行解析。

【讨论】:

    【解决方案8】:

    从字符串解析十进制数的扩展。

    • 无论数字在字符串的开头、结尾还是中间。
    • 无论是只有数量还是很多“垃圾”字母。
    • 无论在 PC 的文化设置中配置什么分隔符:它都会正确解析点和逗号。
    • 能够手动设置十进制符号。

      public static class StringExtension
      {
          public static double DoubleParseAdvanced(this string strToParse, char decimalSymbol = ',')
          {
              string tmp = Regex.Match(strToParse, @"([-]?[0-9]+)([\s])?([0-9]+)?[." + decimalSymbol + "]?([0-9 ]+)?([0-9]+)?").Value;
      
              if (tmp.Length > 0 && strToParse.Contains(tmp))
              {
                  var currDecSeparator = System.Windows.Forms.Application.CurrentCulture.NumberFormat.NumberDecimalSeparator;
      
                  tmp = tmp.Replace(".", currDecSeparator).Replace(decimalSymbol.ToString(), currDecSeparator);
      
                  return double.Parse(tmp);
              }
      
              return 0;
          }
      }
      

    使用方法:

    "It's 4.45 O'clock now".DoubleParseAdvanced(); // will return 4.45
    "It's 4,45 O'clock now".DoubleParseAdvanced(); // will return 4.45
    "It's 4:45 O'clock now".DoubleParseAdvanced(':'); // will return 4.45
    

    【讨论】:

    • 4:45 应该等于 4.75 :P
    • 对于非 winforms 应用使用:var currDecSeparator = Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator;
    • 这在你使用 '.' 时不起作用作为 decimalSymbol 参数。 Assert.AreEqual(4.45d, DoubleParseAdvanced("4.45", '.')); 如果您的 currentCulture.NumberDecimalSeperator 是 ',',则返回 445。
    • 是的,你是对的。需要更新代码。也许以后会做
    • 这你在两种文化中测试这个'。'和“,”?
    【解决方案9】:

    您可以使用

    检查字符串是否包含小数点

    string s="";

            if (s.Contains(','))
            { 
            //treat as double how you wish
            }
    

    然后将其视为小数,否则只需传递非双精度值。

    【讨论】:

      【解决方案10】:

      另一种选择是使用 CultureInfo 类中的小数分隔符信息。知道我们可以用 '.' 替换 ','需要时反之亦然。如果需要对 1,000,000.23 之类的数字进行处理,则此类中还可以使用数字分组符号。

      string decimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
              string value = "";
      
              if (decimalSeparator == ".")
              {
                  value = rateLimitTextBox.Text.Replace(",", ".");
              }
              else if (decimalSeparator == ",")
              {
                  value = rateLimitTextBox.Text.Replace(".", ",");
              }
      
              bool LimitAcceptable = decimal.TryParse(value, NumberStyles.Any, CultureInfo.CurrentCulture, out decimal limit);
      

      【讨论】:

        【解决方案11】:

        如果我想解析带小数点分隔符的数字,我使用以下 sn-p:

        public bool TryParseDecimal(string value, out decimal result) {
            const string your_separator = ",";
        
            var numberFormat = new NumberFormatInfo {
                    NumberDecimalSeparator = your_separator
            };
        
            return decimal.TryParse(value, NumberStyles.AllowDecimalPoint, numberFormat, out result);
        }
        

        我不认为使用文化或字符串操作表达了将数字转换为非“。”的意图。小数点。

        【讨论】:

          【解决方案12】:

          对我来说,使用文化信息不是一种选择,因为该应用程序在具有不同文化的系统上运行,但输入字符串要在未知文化的位置进行解析。

          所以我提到规范化字符串表示,然后使用 CultureInfo.InvariantCulture 进行转换:

              private static double NormalizeAndParse(string strDouble)
              {
                  string strDoubleNormalized;
          
                  if (strDouble.Contains(","))
                  {
                      var strReplaced = strDouble.Replace(",", ".");
                      var decimalSeparatorPos = strReplaced.LastIndexOf('.');
                      var strInteger = strReplaced.Substring(0, decimalSeparatorPos);
                      var strFractional = strReplaced.Substring(decimalSeparatorPos);
          
                      strInteger = strInteger.Replace(".", string.Empty);
                      strDoubleNormalized = strInteger + strFractional;
                  }
                  else
                  {
                      strDoubleNormalized = strDouble;
                  }
          
                  return Double.Parse(strDoubleNormalized, NumberStyles.Any, CultureInfo.InvariantCulture);
              }
          

          【讨论】:

            【解决方案13】:

            试试这个...它对我有用。

            double vdouble = 0;
            string sparam = "2,1";
            
            if ( !Double.TryParse( sparam, NumberStyles.Float, CultureInfo.InvariantCulture, out vdouble ) )
            {
                if ( sparam.IndexOf( '.' ) != -1 )
                {
                    sparam = sparam.Replace( '.', ',' );
                }
                else
                {
                    sparam = sparam.Replace( ',', '.' );
                }
            
                if ( !Double.TryParse( sparam, NumberStyles.Float, CultureInfo.InvariantCulture, out vdouble ) )
                {
                    vdouble = 0;
                }
            }
            

            【讨论】:

              猜你喜欢
              • 2012-10-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-09-17
              • 1970-01-01
              • 2016-04-15
              • 1970-01-01
              相关资源
              最近更新 更多