C#十进制。用逗号分析问题

C#十进制。用逗号分析问题,c#,parsing,decimal,C#,Parsing,Decimal,这是我的问题(对我们来说): Decimal.Parse(“1,2,3,4”)返回1234,而不是抛出InvalidFormatException 大多数Windows应用程序(Excel EN)不丢弃千个分隔符,并且不将该值视为十进制数。其他语言也会出现同样的问题(尽管字符不同) 有没有其他的十进制解析库可以解决这个问题 谢谢 它允许数千,因为Decimal.Parse(NumberStyles.Number)使用的默认值包括NumberStyles.AllowThousands) 如果不允许

这是我的问题(对我们来说):

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

大多数Windows应用程序(Excel EN)不丢弃千个分隔符,并且不将该值视为十进制数。其他语言也会出现同样的问题(尽管字符不同)

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


谢谢

它允许数千,因为
Decimal.Parse
NumberStyles.Number
)使用的默认值包括
NumberStyles.AllowThousands

如果不允许使用数千个分隔符,只需删除该标志,如下所示:

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

(上面的代码将抛出一个
InvalidFormatException
,这正是您想要的,对吗?

您可以通过两个阶段的过程来完成这一点。首先,您可以使用
CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator
CultureInfo.CurrentCulture.NumberFormat.NumberGroupSizes
中的信息验证千位分隔符,如果该分隔符未传递,则引发异常,然后将该数字传递到
Decimal.Parse()

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

我的解决方案如下。它适用于框架中的所有地区。但它不支持负数,正如猎户座在下面指出的那样。你们觉得怎么样

    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):


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

如果您想阅读我的解决方案(它用于我的mvc自定义验证器,但您可以使用它来获得更好的double/decimal/float.parse通用验证器),请访问这里

您是想禁止使用任何千位分隔符,还是只允许使用无关的分隔符?我应该更具体一点(对不起,我是新来的!)。我不允许在字符串中使用额外的千个分隔符。“1234.00”应该是有效的,而“12,34.00”应该是错误的。我认为这不是他想要的。我认为他想把“1200”看作是有效的,而不是“1,2,0,0”…可能是错的。你是对的,Max。我仍然需要千分分离器,当它只分离数千个。我仍然认为解析器是有缺陷的。分隔符应该只允许每三位出现一次,并且只出现在小数点的左侧。我不认为解析器跳过小数分隔符是一个错误,因为这些字符在数学上没有任何意义。但是如果能有一个更严格的方法来解决这个问题,那就太好了……不是真的,约书亚。在en US语言环境中,Decimal.Parse将“123,40”转换为12340.00,而不是123.40。这种行为与其他地区是一致的。谢谢,猎户座,我会尝试一下这个想法。嗨,猎户座,我最终使用了你提到的项目,还有一些。看看我下面答案中的解决方案,你觉得怎么样?在总体使用方面有几个问题。很多区域性都不使用-来表示负号,因此将其包含在正则表达式中会使其不具有区域性。此外,一些编号系统在编号后使用负号,而不是在前面(例如,在美国英语中,对于“-1234”,使用“1234-”。对于某些文化,通常还必须在“-”之前或之后留出空间。此外,一些区域性使用括号表示负数,这意味着成对使用。不管是哪种方式,如果您只在en-US中使用它,那么您应该不会有问题。而且.Net确实支持货币解析。您只需传入NumberStyles选项的货币规则(即NumberStyles.currency)。它只是对分组分隔符有一个更自由的解释。嗨,奥龙,谢谢你的跟进。你说得对,这根本不起作用。这将被全球各地的用户使用,但应用程序不支持负值的输入,所以它对我很有效。@bolu是的,代码的性能不是很好,但你可以随时缓存regex对象,这就是我(几年前)在解决方案中所做的。
    [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;

    }