web-dev-qa-db-fra.com

Convertir une chaîne monétaire en décimal?

Objectif

Triez une string affichant des données monétaires telles que celle-ci $1,995.94 numériquement dans un ensemble de données.

Code

J'utilise actuellement l'exemple de code ci-dessous pour convertir la valeur string en decimal afin de pouvoir la trier correctement.

if (sortBy == "checkAmount")
{
    StringBuilder sb = new StringBuilder();
    foreach (var c in Convert.ToString(p.GetType().GetProperty(sortBy).GetValue(p, null)))
    {
        if (!char.IsDigit(c) && c != '.') { continue; }
        sb.Append(c);
    }
    return Convert.ToDecimal(sb.ToString());
}
else
{
    return p.GetType().GetProperty(sortBy).GetValue(p, null);
}

Problème

Quelle est la meilleure façon de faire cela? Cela fonctionne et c'est cool, mais ce n'est pas très élégant.

Solution finale

La réponse fournie par Servy fonctionne comme prévu , et j'ai utilisé cette implémentation pendant un moment, mais un collègue et moi avons trouvé un moyen encore meilleur, c'est pourquoi je documente ici.BTW, j'ai fini par utiliser cette solution à la fin.

decimal.Parse(input, NumberStyles.AllowCurrencySymbol | NumberStyles.Number);
44
Mike Perrenoud

Voici une méthode qui ressemble le plus au code que vous avez fourni

public static decimal Parse(string input)
{
    return decimal.Parse(Regex.Replace(input, @"[^\d.]", ""));
}

Voici une option qui prendra en charge les nombres négatifs et s’arrêtera si elle trouve une seconde valeur de période, réduisant ainsi le nombre de chaînes renvoyées qui ne sont pas des valeurs decimal valides. Il comporte également quelques autres modifications non visibles dans l'OP pour traiter les cas supplémentaires que votre code actuel ne gère pas.

public static decimal Parse(string input)
{
    return decimal.Parse(Regex.Match(input, @"-?\d{1,3}(,\d{3})*(\.\d+)?").Value);
}
12
Servy

Que diriez-vous de cela, mais ne fonctionne que pour une valeur de chaîne. Donc, vous devez obtenir votre chaîne split par $ et ensuite effectuer la conversion tout en enregistrant dans la array ou list

 using System.Globalization;
    //rest of your code

          string str = "$50,550.20";
          decimal decval;
          bool convt = decimal.TryParse(str, NumberStyles.Currency,
            CultureInfo.CurrentCulture.NumberFormat, out decval);
          if (convt) 
          Console.WriteLine(decval);
          Console.ReadLine();
24
bonCodigo
decimal amount = decimal.Parse("$123,456.78",
NumberStyles.AllowCurrencySymbol |
NumberStyles.AllowThousands |
NumberStyles.AllowDecimalPoint);
8
bilal

Voici une solution plus simple:

    public static decimal ToDecimal(this string str)
    {
        return decimal.Parse(str, NumberStyles.Currency);
    }

et le test unitaire:

    [Test]
    public void ToDecimal_Convert_String_To_Decimal()
    {
        Assert.AreEqual(1234M, "1234".ToDecimal());
        Assert.AreEqual(-1234.56M, "$(1,234.56)".ToDecimal());
        Assert.AreEqual(1234.56M, "$1,234.56".ToDecimal());
    }
7
Red
public static decimal ToDecimalFromStringDecimalOrMoneyFormattedDecimal(this string s)
{
    try
    {
        return decimal.Parse(s);
    }
    catch
    {
        var numberWithoutMoneyFormatting = Regex.Replace(s, @"[^\d.-]", "");
        return decimal.Parse(numberWithoutMoneyFormatting);
    }
}

[Test]
public void Test_ToDecimalFromStringDecimalOrMoneyFormattedDecimal()
{
    Assert.That("$ 500".ToDecimalFromStringDecimalOrMoneyFormattedDecimal() == (decimal)500);
    Assert.That("R -500".ToDecimalFromStringDecimalOrMoneyFormattedDecimal() == (decimal)-500);
    Assert.That("-$ 500".ToDecimalFromStringDecimalOrMoneyFormattedDecimal() == (decimal)-500);
    Assert.That("P 500.90".ToDecimalFromStringDecimalOrMoneyFormattedDecimal() == (decimal)500.9);
    Assert.That("$ -50 0,090,08.08".ToDecimalFromStringDecimalOrMoneyFormattedDecimal() == (decimal)-50009008.08);
}
0
Richard