Convert currency string to decimal?

C#.NetType Conversion

C# Problem Overview


##Objective

Sort a string that is displaying currency data like this $1,995.94 numerically in a set of data.

##Code

I'm currently using the below code sample to convert the string value to decimal so that I can sort it properly.

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);
}

##Problem

What's a better way of doing this? It works, and that's cool, but it's not very elegant.

##Final Solution The answer provided by Servy works as expected, and I used that implementation for a while, but a colleague and I found an even better way so I'm documenting it here. BTW, I ended up using this solution in the end.

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

C# Solutions


Solution 1 - C#

How about this, but only works for one string value. So you need to get your string split by $ and then do the conversion while saving into the array or 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();

Solution 2 - C#

Here is a simpler solution:

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

and the unit test:

    [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());
    }

Solution 3 - C#

Here is a method that most closely resembles the code you've provided

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

Here is an option that will support negative numbers, and will stop if it finds a second period value, thus reducing the number of strings it returns that are not valid decimal values. It also has a few other modifications not seen in the OP to handle additional cases your current code doesn't.

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

Solution 4 - C#

decimal amount = decimal.Parse("$123,456.78",
NumberStyles.AllowCurrencySymbol |
NumberStyles.AllowThousands |
NumberStyles.AllowDecimalPoint);

Solution 5 - C#

works for all culture:

var d = decimal.Parse("$497.7", NumberStyles.Currency, CultureInfo.CreateSpecificCulture("us-US").NumberFormat);	

Console.WriteLine(d);

Solution 6 - C#

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);
}

Solution 7 - C#

We can try to use decimal.TryParse to cast the currency string value to a decimal number.

  • NumberStyles:use NumberStyles.Currency which indicates that all styles except AllowExponent and AllowHexSpecifier are used. This is a composite number style.
  • CultureInfo: we need to set the right culture of currency which align with your currency value.

For this example, $20,000.00 is USA currency we can try to use English (USA) for that, on the other hand 20,000.00€ is euro currency we can try to use English (Ireland) that uses the euro currency.

decimal.TryParse("20,000.00€", NumberStyles.Currency ,CultureInfo.CreateSpecificCulture("en-IE"), out var euro);
Console.WriteLine(euro);
decimal.TryParse("$20,000.00", NumberStyles.Currency ,CultureInfo.CreateSpecificCulture("en-us"), out var dollar);
Console.WriteLine(dollar);

c# online

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMike PerrenoudView Question on Stackoverflow
Solution 1 - C#bonCodigoView Answer on Stackoverflow
Solution 2 - C#RedView Answer on Stackoverflow
Solution 3 - C#ServyView Answer on Stackoverflow
Solution 4 - C#bilalView Answer on Stackoverflow
Solution 5 - C#robertView Answer on Stackoverflow
Solution 6 - C#RichardView Answer on Stackoverflow
Solution 7 - C#D-ShihView Answer on Stackoverflow