Search code examples
c#seleniumcurrency

How to get any currency format to be converted into "de-de" in C#


I get the currency values from a website... they could be in any currency format as the site is various in multiple countries.

what i currently have:

var actualPriceString = actualPriceElement.Text;
var actualPriceDe = Convert.ToDecimal(actualPriceString).ToString("C0", CultureInfo.GetCultureInfo("de-de"));
var maxPriceDe = Convert.ToDecimal(product.Max_Price).ToString("C0", CultureInfo.GetCultureInfo("de-de"));

if (Convert.ToDecimal(actualPriceDe) <= Convert.ToDecimal(maxPriceDe))
  run = await ClickElement(_config.site.add_to_cart, driver);

which just gives me errors or not what I wat at all.

I get errors when convert to decimal:

exception.Message = "Input string was not in a correct format."

The currency formats can look like those for example: 3.399,00 or 3,399.00

I also tried finding results online but all I get is from one currency Format to any other...

Thanks for your help!


Solution

  • You can't solve the problem in general case, however, we can fight for some restricted cases:

    1. We assume that negative value uses simple leading -: -123.456,78
    2. We assume that we have no more than 2 positions for cents
    3. We assume that decimal and group separators are not mixed: 12,45,67 == 123456
    4. 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