5

事实上,我有多个可以生成数字数据的系统,它们以文本文件的形式存储在某个 Web 服务器上。有些系统使用小数点作为分数分隔符,有些系统同样使用小数点逗号。

应用程序(胖客户端,.net 2.0)也可以在任何一种系统上运行。

因此,经过一番磕磕绊绊,我做到了:(http://pastebin.com/vhLXABDD

    public static bool HasDecimalComma;
    public static bool HasDecimalPeriod;

    public static double GetNumber(string NumberString)
    {
        if (!HasDecimalComma && !HasDecimalPeriod)
        {
            string s = string.Format("{0:0.0}", 123.123);
            if (s.Contains('.'))
            {
                HasDecimalPeriod = true;
            }
            else if (s.Contains(','))
            {
                HasDecimalComma = true;
            }
            else
            {
                throw new SystemException(string.Format("strange number format '{0}'", s));
            }
        }
        if (HasDecimalComma)
        {
            return double.Parse(NumberString.Replace('.', ','));
        }
        if (HasDecimalPeriod)
        {
            return double.Parse(NumberString.Replace(',', '.'));
        }
        throw new ArgumentException(string.Format("can't parse '{0}'", NumberString));
    }

你会建议更好,更优雅的方式吗?

编辑:

我很抱歉之前没有提到它,并且由于您的答案倾向于那个方向 - 我无法用数字存储生成文化,我只能尝试“检测”它。

4

4 回答 4

3

试试这个:

    static double GetDouble(string s)
    {
        double d;

        var formatinfo = new NumberFormatInfo();

        formatinfo.NumberDecimalSeparator = ".";

        if (double.TryParse(s, NumberStyles.Float, formatinfo, out d))
        {
            return d;
        }

        formatinfo.NumberDecimalSeparator = ",";

        if (double.TryParse(s, NumberStyles.Float, formatinfo, out d))
        {
            return d;
        }

        throw new SystemException(string.Format("strange number format '{0}'", s));
    }
于 2013-09-02T11:19:22.247 回答
1

如果您无法更改呼叫站点,并且您保证在小数分隔符旁边不会出现其他类型的分隔符,那么您可以或多或少地使用您的方法。我会建议

  1. HasDecimalCommaandHasDecimalPeriod移到方法的主体 - 在这种情况下,绝对不需要全局状态。
  2. 使用TryParse而不是Parse,因为预计这些数字可能存在错误。
  3. 明确指定InvariantCulture文化(它有一个小数点)。
  4. 允许既没有逗号也没有句点的数字,因为“3”毕竟是一个浮点数。

所以沿着这些思路:

///comment the method assumptions here
///otherwise the method might seem wrong
public static double GetNumber(string numberString)
{
   bool hasDecimalComma = numberString.Contains(',');
   if (hasDecimalComma)
     numberString = numberString.Replace(',', '.')
   double result;
   bool success = double.TryParse(numberString, 
                      NumberStyles.Float, 
                      CultureInfo.InvariantCulture,
                      out result);
   if (success)
     return result;
   else 
     throw new ArgumentException(
                           string.Format("can't parse '{0}'", numberString));
}

(旧答案,原则上好,实践中不可能)

我建议将生成的区域性存储在字符串中,然后使用它来调用方法,沿着这些线(使用double.TryParse):

public static double GetNumber(string numberString, CultureInfo culture)
{
   double result;
   bool success = double.TryParse(numberString, 
                          NumberStyles.Float | NumberStyles.AllowThousands, 
                          culture,
                          out result);
   if (success)
      return result;
   else 
      throw new ArgumentException(
                               string.Format("can't parse '{0}'", numberString));
}
于 2013-09-02T11:06:49.150 回答
0

只需使用当前的文化和正确的数字格式标志。当然,您必须针对可能存储在数据库中的所有文化对其进行测试。更好:将数字转换为 CultureInfo.Invariant 文化,然后再将它们存储到数据库中。或者:存储数字时也存储文化标识符。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            const string toTest = "1.006,30";

            float number;
            if (float.TryParse(toTest, NumberStyles.AllowDecimalPoint | NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.CurrentCulture, out number))
                Console.WriteLine("Success: {0}", number);
            else
                Console.WriteLine("Failure: strange number format");

            Console.WriteLine("Press any key to finish");
            Console.ReadKey();
        }
    }
}
于 2013-09-02T12:54:37.130 回答
0

除非您的某些客户使用波斯语(fa,fa-IR标签)作为他们的文化,否则我认为您很高兴:

// apparently, Persians use '/' as the decimal separator
var slash = CultureInfo
    .GetCultures(CultureTypes.AllCultures)
    .Where(c => 
        c.NumberFormat.NumberDecimalSeparator != "," && 
        c.NumberFormat.NumberDecimalSeparator != ".")
    .ToList();
于 2013-09-06T13:31:11.793 回答