Преобразовать строку в десятичную, с запятыми и точками

#c# #parsing #decimal

#c# #синтаксический анализ #десятичная

Вопрос:

Как преобразовать строку в десятичную, чтобы она работала для обоих форматов — с запятыми и точками?

 [Fact]
public void foo(){
  var a="1,1";
  var b="1.1";
  Assert.Equal(Parse(a),Parse(b));
}
private decimal Parse(string s){
  return decimal.Parse(s,NumberStyles.Any,
    CultureInfo.InvariantCulture);
}
  

вывод:

 Test 'Unit.Sandbox.foo' failed: Assert.Equal() Failure
Expected: 11
Actual:   1,1
  

Комментарии:

1. Даже если она будет проанализирована, почему они должны быть равны? Один равен 1 точке 1, другой равен одиннадцати …? (поскольку вы явно указываете инвариантную культуру)

2. @Marc Gravell Я не уверен, что правильно вас понял. В любом случае — цель состоит в том, чтобы написать функцию синтаксического анализа, чтобы она понимала оба формата. Утверждение отражает то, чего я пытаюсь достичь.

3. @Arnis: Я полагаю, Марк имел в виду неоднозначность поддержки как десятичной точки, так и разделителя тысяч с использованием разных культур. Но я полагаю, что вас интересует только разбор десятичных точек?

4. @Arnis — Я понимаю , но: оба являются допустимыми числами как в языке «.=point», так и в языке «,=point». Как вы предлагаете понять, что предназначено? В «1,1» вы, возможно, могли бы подделать это, но как насчет «1,001» против «1,001»? Это одно и то же? Независимо от того, используете ли вы или . в качестве «точки», единица равна тысяче и одному, а другая равна одной точке ноль ноль один.

5. @Marc напоминает мне сообщение Джона в блоге «Humanity fail» bit.ly/kQUJcR T_T

Ответ №1:

Вы могли бы попробовать это:

 private decimal Parse(string s){
  s = s.Replace(",", CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator);
  return decimal.Parse(s,NumberStyles.Any,
    CultureInfo.InvariantCulture);
}
  

Комментарии:

1. Если OP хочет поддерживать тысячи символов-разделителей, то это не сработает.

2. @Groo, действительно, но я не вижу, как он мог бы поддерживать разделитель тысяч, если и запятая, и точка должны обрабатываться одинаково…

3. @Thomas это невозможно … 🙁

4. @Arnis L., что невозможно?

5. @Arnis L., это сработает, если вы решите не использовать разделитель тысяч

Ответ №2:

Как насчет этого?

 private static decimal Parse(string s)
    {
        s = s.Replace(",", ".");
        return decimal.Parse(s);
    }
  

Комментарии:

1. попробуйте сами: 1.000.000, 25 и 1000000.25

Ответ №3:

Вы должны получить желаемый результат, изменив разделитель десятичной валюты на запятую перед разбором десятичной строки через запятую. Здесь есть несколько полезных ресурсов:

http://msdn.microsoft.com/en-us/library/system.globalization.numberformatinfo.currencydecimalseparator.aspx#Y888

В качестве альтернативы вы могли бы реализовать свой собственный Iformatprovider, как обсуждалось здесь:

http://msdn.microsoft.com/en-us/library/t7xswkc6.aspx http://msdn.microsoft.com/en-us/library/system.globalization.numberformatinfo.aspx

О, или вы могли бы сделать грязный взлом и просто выполнить замену строки на «,» на «.» 😉

Ответ №4:

Если у вас англоязычная операционная система, этот метод преобразует десятичное число с запятой в точку. Если вы владеете русским языком, метод преобразует десятичное число с точкой в запятую.

 Console.Write("Input number: ");
string? input = Console.ReadLine();
decimal number = ConvertNumberToCurrentLocale(input);
Console.WriteLine("Result: "   number);

decimal ConvertNumberToCurrentLocale(string? input)
{
    string separator = Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator;
    switch (separator)
    {
        case ".":
            input = input?.Replace(",", ".");
            break;
        case ",":
            input = input?.Replace(".", ",");
            break;
    }
    decimal.TryParse(input, out var number);
    return number;
}