You can't solve the problem in general case, however, we can fight for some restricted cases:
- We assume that negative value uses simple leading
-: -123.456,78
- We assume that we have no more than
2 positions for cents
- We assume that decimal and group separators are not mixed:
12,45,67 == 123456
- We ignore currency symbols, all sums are assumed to be in euro
Code:
public static decimal MyConversion(string value) {
if (string.IsNullOrWhiteSpace(value))
throw new FormatException("Not a valid currency");
value = string.Concat(value
.Reverse()
.SkipWhile(c => !char.IsDigit(c))
.Reverse()
.SkipWhile(c => !char.IsDigit(c) && c != '-'));
HashSet<char> separators = new HashSet<char>();
int suggestSeparatorIndex = -1;
StringBuilder sb = new StringBuilder(value.Length);
for (int i = 0; i < value.Length; ++i) {
char c = value[i];
if (char.IsDigit(c))
sb.Append(c);
else if (c == '-' && i == 0)
sb.Append(c);
else if (!char.IsWhiteSpace(c))
if (separators.Add(c))
suggestSeparatorIndex = sb.Length;
else
suggestSeparatorIndex = -1;
}
if (suggestSeparatorIndex >= 0 && suggestSeparatorIndex >= sb.Length - 2)
sb.Insert(suggestSeparatorIndex, '.');
return decimal.Parse(sb.ToString(), CultureInfo.InvariantCulture) + 0.00m;
}
Demo:
string[] tests = new string[] {
"3.399,00",
"3,399.00",
"123,345,789.0",
"123.1",
"12.23.45", // here '.' is a group separator
"123",
"456 $ 89 cents", // we ignore $ here, no currency exchange will be done
"$56.89",
"123=35 (euro)",
"56 Евро 89 центов", // Russian, stands for 56 Euro 89 cents
};
// Deutschland Kultur (German Culture settings)
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("de-De");
string report = string.Join(Environment.NewLine, tests
.Select(test => $"{test,25} => {MyConversion(test)}"));
Console.Write(report);
Outcome:
3.399,00 => 3399,00
3,399.00 => 3399,00
123,345,789.0 => 123345789,00
123.1 => 123,10
12.23.45 => 122345,00
123 => 123,00
456 $ 89 cents => 456,89
$56.89 => 56,89
123=35 (euro) => 123,35
56 Евро 89 центов => 56,89