Лучший способ преобразовать строку в десятичный разделитель "." и "," нечувствительный способ? - PullRequest
19 голосов
/ 04 ноября 2010

Приложение имеет дело со строками, представляющими десятичные числа, которые происходят из разных культур. Например, «1.1 и« 1,1 »- это одно и то же значение.

Я играл с Decimal.TryParse комбинациями флагов, но не смог достичь желаемого результата. «1,1» стало «11» или «0» в конце концов.

Можно ли преобразовать такие строки в десятичные в одной строке кода без предварительной замены "," char на "." или играет с NumberFormat.NumberDecimalSeparator?

Как вы справляетесь с такими ситуациями?

Заранее спасибо!

Ответы [ 7 ]

32 голосов
/ 04 ноября 2010

Вы можете создать временный объект CultureInfo для использования при синтаксическом анализе.

// get a temporary culture (clone) to modify
var ci = CultureInfo.InvariantCulture.Clone() as CultureInfo;
ci.NumberFormat.NumberDecimalSeparator = ",";
decimal number = decimal.Parse("1,1", ci); // 1.1
11 голосов
/ 24 июля 2014

Я нашел другой способ сделать это.Это выглядит странно, но прекрасно работает для меня.

Так что, если вы не знаете культуру целевой системы и не знаете, какое значение вы получите, например, 12,33 или 12,33, вы можете сделать следующее

string amount = "12.33";
// or i.e. string amount = "12,33";

var c = System.Threading.Thread.CurrentThread.CurrentCulture;
var s = c.NumberFormat.CurrencyDecimalSeparator;

amount = amount.Replace(",", s);
amount = amount.Replace(".", s);

decimal transactionAmount = Convert.ToDecimal(amount); 
6 голосов
/ 04 ноября 2010

У вас есть следующие возможности:

  1. Ты знаешь культуру
    1. Использовать текущую настройку культуры, для которой установлен компьютер
    2. Вы позволяете пользователю решить установить свою культуру -> пользовательские настройки в вашей программе
  2. Вы не знаете культуру
    1. Вы должны принять решение об этом: вы должны определить и задокументировать свое решение
    2. Угадай: ты пытаешься разобрать, и пытаешься разобрать, и пытаешься ... пока не получишь действительные числа
4 голосов
/ 04 ноября 2010

При вызове Parse вам просто нужно правильно установить культуру, например:

string s = "11,20";

decimal c1 = decimal.Parse(s, new CultureInfo("fr-FR"));
decimal c2 = decimal.Parse(s, new CultureInfo("en-AU"));

Console.WriteLine(c1);
Console.WriteLine(c2);
3 голосов
/ 18 января 2011

Ниже моя реализация, любой хороший идеар?

/// <summary>
/// 
/// </summary>
public static class NumberExtensions
{
    /// <summary>
    /// Convert string value to decimal ignore the culture.
    /// </summary>
    /// <param name="value">The value.</param>
    /// <returns>Decimal value.</returns>
    public static decimal ToDecimal ( this string value )
    {
        decimal number;
        string tempValue = value;

        var punctuation = value.Where ( x => char.IsPunctuation ( x ) ).Distinct ( );
        int count = punctuation.Count ( );

        NumberFormatInfo format = CultureInfo.InvariantCulture.NumberFormat;
        switch ( count )
        {
            case 0:
                break;
            case 1:
                tempValue = value.Replace ( ",", "." );
                break;
            case 2:
                if ( punctuation.ElementAt ( 0 ) == '.' )
                    tempValue = value.SwapChar ( '.', ',' );
                break;
            default:
                throw new InvalidCastException ( );
        }

        number = decimal.Parse ( tempValue, format );
        return number;
    }
    /// <summary>
    /// Swaps the char.
    /// </summary>
    /// <param name="value">The value.</param>
    /// <param name="from">From.</param>
    /// <param name="to">To.</param>
    /// <returns></returns>
    public static string SwapChar ( this string value, char from, char to )
    {
        if ( value == null )
            throw new ArgumentNullException ( "value" );

        StringBuilder builder = new StringBuilder ( );

        foreach ( var item in value )
        {
            char c = item;
            if ( c == from )
                c = to;
            else if ( c == to )
                c = from;

            builder.Append ( c );
        }
        return builder.ToString ( );
    }
}

[TestClass]
public class NumberTest
{

    /// <summary>
    /// 
    /// </summary>
    [TestMethod]
    public void Convert_To_Decimal_Test ( )
    {
        string v1 = "123.4";
        string v2 = "123,4";
        string v3 = "1,234.5";
        string v4 = "1.234,5";
        string v5 = "123";
        string v6 = "1,234,567.89";
        string v7 = "1.234.567,89";

        decimal a1 = v1.ToDecimal ( );
        decimal a2 = v2.ToDecimal ( );
        decimal a3 = v3.ToDecimal ( );
        decimal a4 = v4.ToDecimal ( );
        decimal a5 = v5.ToDecimal ( );
        decimal a6 = v6.ToDecimal ( );
        decimal a7 = v7.ToDecimal ( );

        Assert.AreEqual ( ( decimal ) 123.4, a1 );
        Assert.AreEqual ( ( decimal ) 123.4, a2 );
        Assert.AreEqual ( ( decimal ) 1234.5, a3 );
        Assert.AreEqual ( ( decimal ) 1234.5, a4 );
        Assert.AreEqual ( ( decimal ) 123, a5 );
        Assert.AreEqual ( ( decimal ) 1234567.89, a6 );
        Assert.AreEqual ( ( decimal ) 1234567.89, a7 );
    }
    /// <summary>
    /// 
    /// </summary>
    [TestMethod]
    public void Swap_Char_Test ( )
    {
        string v6 = "1,234,567.89";
        string v7 = "1.234.567,89";

        string a1 = v6.SwapChar ( ',', '.' );
        string a2 = v7.SwapChar ( ',', '.' );

        Assert.AreEqual ( "1.234.567,89", a1 );
        Assert.AreEqual ( "1,234,567.89", a2 );
    }
}
2 голосов
/ 22 сентября 2011

хорошо, но это не на 100% правильно.когда вы используете случай 1: вы автоматически предполагаете, что ',' обозначает десятичную цифру.Вы должны по крайней мере проверить, происходит ли это более одного раза, потому что в этом случае это символ, разделяющий группу

0 голосов
/ 02 апреля 2019

Дважды используйте TryParse с двумя стилями, представляющими две возможности.
Если только один возвращает значение, используйте это значение. Если оба возвращают значение, используйте меньшее значение в абсолютных значениях.

TryParse вернет 0 для чиселкоторые используют как группировку, так и десятичный разделитель, если вы используете неправильный стиль, но если у вас нет разделителя группировки в вашей строке (например, число меньше 1000), он вернет значение в обоих случаях, но «неправильный» номер будетбыть больше (опять же в абсолютном выражении)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...