Подтвердить что ты не робот

С# Decimal.Parse issue с ​​запятыми

Здесь моя проблема (для en-US):

Decimal.Parse("1,2,3,4") возвращает 1234 вместо того, чтобы бросать исключение InvalidFormat.

Большинство приложений Windows (Excel en-US) не отбрасывают тысячи разделителей и не считают это значение десятичным числом. Такая же проблема возникает и для других языков (хотя и с разными символами).

Существуют ли какие-либо другие библиотеки разборного десятичного разбора, которые решают эту проблему?

Спасибо!

4b9b3361

Ответ 1

Мне пришлось написать код для проверки валюты вручную. Лично для рамки, которая гордится тем, что все вещи, связанные с глобализацией, встроены, удивительно,.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):

    [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;

    }

Ответ 2

Это позволяет тысячам, поскольку значение NumberStyles по умолчанию NumberStyles, используемое Decimal.Parse (NumberStyles.Number), включает NumberStyles.AllowThousands.

Если вы хотите запретить разделители тысяч, вы можете просто удалить этот флаг, например:

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

(приведенный выше код выведет InvalidFormatException, что вы хотите, правильно?)

Ответ 3

Возможно, вы сможете сделать это в двухэтапном процессе. Сначала вы можете проверить разделитель тысяч, используя информацию в CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator и CultureInfo.CurrentCulture.NumberFormat.NumberGroupSizes, бросая исключение, если оно не пройдет, а затем передайте число в Decimal.Parse();

Ответ 4

Это обычная проблема, которая никогда не решалась Microsoft. Итак, я не понимаю, почему действует 1,2,3.00 (например, английская культура)! Вам нужно построить алгоритм для изучения размера группы и вернуть false/exception (например, неудачный double.parse), если тест не передан. У меня была аналогичная проблема в приложении mvc, в котором встроенный валидатор не принимает тысячи. Так что я перезаписал его с помощью custom, используя double/decimal/float.parse, но добавив логику для проверки размера группы.

Если вы хотите прочитать мое решение (оно используется для моего стандартного валидатора mvc, но вы можете использовать его, чтобы иметь лучший валидатор double/decimal/float.parse). fooobar.com/info/211767/...