I have looked to multiple SO questions on parsing currency, the best (recommended) way seems to be the one I\'m trying below:
var payout = decimal.Parse(\"$2.10\
You can try like this:
decimal currencyValue;
string inputCurrency = "$12.6";
if (decimal.TryParse(inputCurrency, NumberStyles.Currency, CultureInfo.CreateSpecificCulture("en-US"), out currencyValue))
{
// proceed with currencyValue
}
else
{
//Show error ; Conversion failed
}
For dealing with all currencies you can use the following:
Dictionary<char, string> currencyCulture = new Dictionary<char, string>();
currencyCulture.Add('$', "en-US");
currencyCulture.Add('€', "en-IE");
// populate all posible values here
decimal currencyValue;
string inputCurrency = "€2,66";
char currencySymbol= inputCurrency.ToCharArray()[0];
CultureInfo currentCulture= CultureInfo.CreateSpecificCulture(currencyCulture[currencySymbol]);
if (decimal.TryParse(inputCurrency, NumberStyles.Currency, currentCulture, out currencyValue))
{
// proceed with currencyValue
}
else
{
//Show error ; Conversion failed
}
You can choose culture Names from here
I've expounded on Hari Prasad's answer. With this you can minimize the culture result. Update "SupportedCultures" with the ones you might use in your app.
private static readonly List<string> SupportedCultures = new List<string> {"en-US", "en-GB", "fr-FR"};
public static void Main()
{
var (amount, culture) = ParseCurrencyWithSymbol("$256.12");
Console.WriteLine($"{culture?.Name} | {amount}");
var (amount2, culture2) = ParseCurrencyWithSymbol("£389.17");
Console.WriteLine($"{culture2?.Name} | {amount2}");
var (amount3, culture3) = ParseCurrencyWithSymbol("€421,10");
Console.WriteLine(culture3 != null ? $"{culture3.Name} | {amount3}" : "Failed!");
}
public static Tuple<decimal?, CultureInfo> ParseCurrencyWithSymbol(string input)
{
var culture = CultureInfo.GetCultures(CultureTypes.AllCultures)
.Where(x => SupportedCultures.Contains(x.Name))
.FirstOrDefault(c => input.Contains(c.NumberFormat.CurrencySymbol));
if (culture == null) return new Tuple<decimal?, CultureInfo>(null, null);
return new Tuple<decimal?, CultureInfo>(decimal.Parse(input,
NumberStyles.Currency | NumberStyles.AllowCurrencySymbol |
NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands, culture), culture);
}
Similar approach @un-lucky mentioned as one of the answer, I tried making it generic and work for every Symbol/Format
public static decimal ParseCurrencyWithSymbol(string input)
{
var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures)
.GroupBy(c=> c.NumberFormat.CurrencySymbol)
.ToDictionary(c=> c.Key, c=>c.First());
var culture = cultures.FirstOrDefault(c=>input.Contains(c.Key));
decimal result = 0;
if(!culture.Equals(default(KeyValuePair<string,CultureInfo>)))
{
result = decimal.Parse(input, NumberStyles.Currency | NumberStyles.AllowDecimalPoint, culture.Value);
}
else
{
if( !decimal.TryParse(input, out result))
{
throw new Exception("Invalid number format");
}
}
return result;
}
Usage
decimal output = ParseCurrencyWithSymbol("$2.10");
Working Code
How about a CleanCurrency
method?
/// Loops each char in the string and returns only numbers, . or ,
static double? CleanCurrency(string currencyStringIn) {
string temp = "";
int n;
for (int i = 0; i < currencyStringIn.Length; i++) {
string c = currencyStringIn.Substring(i, 1);
if (int.TryParse(c, out n) || c == "." || c == ",") {
temp += c;
}
}
if (temp == "") {
return null;
else {
return double.Parse("0" + temp);
}
}
The idea here being to just get an actual number regardless of what the string content is.
double? payout = CleanCurrency("$3.50");
Pertinent to your particular case, you may use the following code snippet:
var payout = decimal.Parse("$2.10".Replace("$",""));
If you don't know what the currency symbol would be, then try the following solution:
string _money = "$2.10";
var payout = decimal.Parse(_money.Substring(1));
Dealing with commas and decimal points is much more difficult: if this is the issue, refer to the solution given by member @un-lucky.
Hope this may help.