跨区域十进制/双重解析

时间:2013-09-02 10:58:38

标签: c# parsing regional-settings

事实上,我有多个系统可以生成数字数据,并且它们存储在文本文件中的某个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 个答案:

答案 0 :(得分:2)

试试这个:

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

答案 1 :(得分:0)

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

  1. HasDecimalCommaHasDecimalPeriod移动到方法的主体 - 在这种情况下绝对不需要全局状态。
  2. 使用TryParse代替Parse,因为预计这些数字可能有问题。
  3. 明确指定InvariantCulture文化(它有一个小数句点)。
  4. 允许没有逗号和句点的号码,因为“3”毕竟是一个浮点数。
  5. 这些内容如下:

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

答案 2 :(得分: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();
        }
    }
}

答案 3 :(得分:0)

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

// apparently, Persians use '/' as the decimal separator
var slash = CultureInfo
    .GetCultures(CultureTypes.AllCultures)
    .Where(c => 
        c.NumberFormat.NumberDecimalSeparator != "," && 
        c.NumberFormat.NumberDecimalSeparator != ".")
    .ToList();