22

这是我的问题(对于 en-US):

Decimal.Parse("1,2,3,4")返回 1234,而不是抛出 InvalidFormatException。

大多数 Windows 应用程序 (Excel en-US) 不会删除千位分隔符,也不认为该值是十进制数。其他语言也会出现同样的问题(尽管字符不同)。

有没有其他十进制解析库可以解决这个问题?

谢谢!

4

4 回答 4

14

它允许数千个,因为( )NumberStyles使用的默认值包括.Decimal.ParseNumberStyles.NumberNumberStyles.AllowThousands

如果您想禁止千位分隔符,您可以删除该标志,如下所示:

Decimal.Parse("1,2,3,4", NumberStyles.Number ^ NumberStyles.AllowThousands)

(上面的代码会抛出一个InvalidFormatException,这就是你想要的,对吧?)

于 2009-05-06T21:08:44.437 回答
10

我最终不得不编写代码来手动验证货币。就个人而言,对于一个以内置所有全球化内容而自豪的框架,令人惊讶的是.NET 没有任何东西可以处理这个问题。

我的解决方案如下。它适用于框架中的所有语言环境。不过,正如 Orion 在下面指出的那样,它不支持负数。你们有什么感想?

    public static bool TryParseCurrency(string value, out decimal result)
    {
        result = 0;
        const int maxCount = 100;
        if (String.IsNullOrEmpty(value))
            return false;

        const string decimalNumberPattern = @"^\-?[0-9]{{1,{4}}}(\{0}[0-9]{{{2}}})*(\{0}[0-9]{{{3}}})*(\{1}[0-9]+)*$";

        NumberFormatInfo format = CultureInfo.CurrentCulture.NumberFormat;

        int secondaryGroupSize = format.CurrencyGroupSizes.Length > 1
                ? format.CurrencyGroupSizes[1]
                : format.CurrencyGroupSizes[0];

        var r = new Regex(String.Format(decimalNumberPattern
                                       , format.CurrencyGroupSeparator==" " ? "s" : format.CurrencyGroupSeparator
                                       , format.CurrencyDecimalSeparator
                                       , secondaryGroupSize
                                       , format.CurrencyGroupSizes[0]
                                       , maxCount), RegexOptions.Compiled | RegexOptions.CultureInvariant);
        return !r.IsMatch(value.Trim()) ? false : Decimal.TryParse(value, NumberStyles.Any, CultureInfo.CurrentCulture, out result);
    }

这是一个显示它工作的测试(nUnit):

    [Test]
    public void TestCurrencyStrictParsingInAllLocales()
    {
        var originalCulture = CultureInfo.CurrentCulture;
        var cultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
        const decimal originalNumber = 12345678.98m;
        foreach(var culture in cultures)
        {
            var stringValue = originalNumber.ToCurrencyWithoutSymbolFormat();
            decimal resultNumber = 0;
            Assert.IsTrue(DecimalUtils.TryParseCurrency(stringValue, out resultNumber));
            Assert.AreEqual(originalNumber, resultNumber);
        }
        System.Threading.Thread.CurrentThread.CurrentCulture = originalCulture;

    }
于 2009-05-08T02:38:05.027 回答
1

您可以分两阶段进行。首先,您可以使用 中的信息验证千位分隔符,CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator如果CultureInfo.CurrentCulture.NumberFormat.NumberGroupSizes未通过则抛出异常,然后将数字传递给Decimal.Parse();

于 2009-05-06T21:20:10.617 回答
0

这是微软从未解决的常见问题。所以,我不明白为什么 1,2,3.00(例如英语文化)是有效的!如果测试未通过,您需要构建一个算法来检查组大小并返回错误/异常(如失败的 double.parse)。我在 mvc 应用程序中遇到了类似的问题,它内置的验证器不接受数千..所以我用自定义覆盖它,使用 double/decimal/float.parse,但添加了一个逻辑来验证组大小。

如果您想阅读我的解决方案(它用于我的 mvc 自定义验证器,但您可以使用它来获得更好的 double/decimal/float.parse 通用验证器)去这里 https://stackoverflow.com/a/41916721/3930528

于 2017-01-29T09:01:46.427 回答